当前位置: 首页 > news >正文

Java基础加强13-集合框架、Stream流

前言:

这个系列记录了我学习面向语言Java的完整过程,可以当作笔记使用。

每篇文章都包含可运行的代码示例和常见错误分析,尤其适合没有编程经验的读者。学习时建议先准备好安装JDK(Java Development Kit)和IDEA(IntelliJ IDEA集成开发环境),随时尝试修改示例代码。

集合框架:

一,认识集合:

1,介绍:

2,集合体系结构:

二,Collection集合:

1,介绍:

2,Collection的常用方法:

3,Collection的三种遍历方式:

I,迭代器遍历:

示例:

public static void main(String[] args) {//目标:掌控Collection的遍历方式一:迭代器ArrayList<String> list = new ArrayList<>();list.add("hello");list.add("world");list.add("java");System.out.println(list);//1,得到这个集合的迭代器对象Iterator<String> it = list.iterator();while (it.hasNext()) {//2,调用next方法,获取集合中的元素String s = it.next();//迭代器会得到当前的元素,并移动到下一个位置System.out.println(s);}
}

II,增强for循环遍历:

示例:

public static void main(String[] args) {//目标:掌控Collection的遍历方式二:增强forArrayList<String> list = new ArrayList<>();//集合list.add("hello");list.add("world");list.add("java");for(String s:list){System.out.println(s);}String[] arr = {"hello","world","java"};//数组for(String s:arr){System.out.println(s);}
}

III,Lambda表达式遍历:

示例:

public static void main(String[] args) {//目标:掌控Collection的遍历方式三:lambdaArrayList<String> list = new ArrayList<>();//集合list.add("hello");list.add("world");list.add("java");//        list.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });//lambda表达式简化list.forEach(s -> System.out.println(s));
}

IV,三种遍历方式的区别:

认识并发修改异常问题:

示例:

public static void main(String[] args) {//目标:认识并发修改异常问题,高清楚每种遍历的区别ArrayList<String> list = new ArrayList<>();list.add("Java入门");list.add("宁夏枸杞");list.add("黑枸杞");list.add("枸杞子");list.add("特级枸杞");//需求1:删除全部枸杞for(int i=0;i<list.size();i++){String s = list.get(i);if(s.contains("枸杞")){list.remove(s);}}System.out.println(list);//[Java入门, 黑枸杞, 特级枸杞]//出现并发修改异常System.out.println("===================================");//解决方案1:ArrayList<String> list2 = new ArrayList<>();list2.add("Java入门");list2.add("宁夏枸杞");list2.add("黑枸杞");list2.add("枸杞子");list2.add("特级枸杞");for(int i=0;i<list2.size();i++){String s = list2.get(i);if(s.contains("枸杞")){list2.remove(s);i--;}}System.out.println(list2);System.out.println("===================================");//解决方案2:ArrayList<String> list3 = new ArrayList<>();list3.add("Java入门");list3.add("宁夏枸杞");list3.add("黑枸杞");list3.add("枸杞子");list3.add("特级枸杞");for(int i=list3.size()-1;i>=0;i--){String s = list3.get(i);if(s.contains("枸杞")){list3.remove(s);}}System.out.println(list3);System.out.println("===================================");ArrayList<String> list4 = new ArrayList<>();list4.add("Java入门");list4.add("宁夏枸杞");list4.add("黑枸杞");list4.add("枸杞子");list4.add("特级枸杞");//迭代器遍历删除也存在并发修改异常问题//可以解决:使用迭代器直接的方法来删除Iterator<String> it = list4.iterator();while(it.hasNext()){String s = it.next();if(s.contains("枸杞")){//list4.remove(s);//出现并发修改异常it.remove();}}System.out.println(list4);//如果用增强for循环和Lambda表达式来删除,也会出现并发修改异常//结论:增强for循环和Lambda只适合做遍历,不适合做遍历并修改操作
//        for(String s:list4){
//            if(s.contains("枸杞")){
//                list4.remove(s);
//            }
//        }
//        System.out.println(list4);//        list4.forEach(s -> {
//            if(s.contains("枸杞")){
//                list4.remove(s);
//            }
//        });
//        System.out.println(list4);
}

总结

解决并发修改异常问题的方案:

4,List家族的集合:

I,List集合的特有方法:

示例:

public static void main(String[] args) {//目标:搞清楚Collection集合的整体特点//1,List家族的集合,有序、可重复、有索引List<String> list = new ArrayList();//多态性list.add("hello");list.add("world");list.add("java");System.out.println(list);//[hello, world, java]list.add(1,"鸿蒙");//索引插入System.out.println(list); // [hello, 鸿蒙, world, java]list.remove(0);//索引删除    System.out.println( list);// [鸿蒙, world, java]list.set(2,"java精通");//索引修改System.out.println(list);//  [鸿蒙, world, java精通]System.out.println(list.get(0));//索引访问   输出:鸿蒙
}

II,ArrayList 的底层原理:

III,LinkedList 的底层原理:

基于双链表实现:

IV,LinkedList新增了很多首尾操作的特有方法:

V,LinkedList的常见应用场景:

设计队列:

设计栈:

注:方法push跟方法addFirst用法作用相同,方法pop跟方法removeFirst用法作用相同

方法push是方法addFirst的包装,方法pop是方法removeFirst的包装。

5,Set家族的集合:

I,认识:

public static void main(String[] args){//目标:认识Set家族集合的特点//1,创建一个Set集合,特点:无序、不可重复、无索引Set<String> set = new HashSet<>();//无序、不可重复、无索引//Set<String> set = new LinkedHashSet<>();//有序、不可重复、无索引set.add("hello");set.add("hello");set.add("world");set.add("world");set.add("java");set.add("java");set.add("鸿蒙");set.add("大数据");System.out.println(set);//[java, 鸿蒙, 大数据, world, hello]//2,创建一个TreeSet集合,特点:有序(默认一定按大小升序排列)、不可重复、无索引Set<Double> set1 = new TreeSet<>();set1.add(10.0);set1.add(10.0);set1.add(5.0);set1.add(20.0);set1.add(15.0);System.out.println(set1);//[5.0, 10.0, 15.0, 20.0]Set<String> set2 = new TreeSet<>();set2.add("hello");set2.add("world");set2.add("java");System.out.println(set2);//[hello, java, world]}

II,HashSet集合的底层原理:

注:当前数组元素不为null的数量超过(当前数组长度 * 默认加载因子 )(例如:16*0.75=12)的时候则进行扩容,扩容到原来的2倍

III,HashSet 集合元素的去重操作:

HashSet 集合去重复的机制:

示例:

import java.util.HashSet;public class SetDemo2 {public static void main(String[] args){//目标:掌握HashSet集合去重操作Student s1 = new Student("张三", 18);Student s2 = new Student("张三", 18);Student s3 = new Student("李四", 28);Student s4 = new Student("李四", 28);HashSet<Student> set = new HashSet<>();set.add(s1);set.add(s2);set.add(s3);set.add(s4);System.out.println(set);}
}
public class Student {private String name;private int age;//getset方法//省略……//有参、无参构造//省略……// 只要两个对象的内容一样结果一定是 true。// s3.equals (s1)@Overridepublic boolean equals(Object o) {if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}'+"\n";}
}

运行结果:

IV,LinkedHashSet 的底层原理:

V,TreeSet集合(指定大小排序规则):

结论:TreeSet集合默不能给自定义对象排序,因为不知道大小规则
如果一定要解决在,怎么办?两种方案:
1,对象类实现一个Comparable接口,并重写compareTo方法,指定大小排序规则

import java.util.Set;
import java.util.TreeSet;public class SetDemo3 {public static void main(String[] args){//目标:搞清楚TreeSet集合对于自定义对象的排序Set<Teacher> set = new TreeSet<>();//排序、不重复、无索引set.add(new Teacher("张三", 28, 3000));set.add(new Teacher("李四", 21, 14000));set.add(new Teacher("小赵", 18, 5000));set.add(new Teacher("小虎", 8, 2000));System.out.println(set);//结论:TreeSet集合默不能给自定义对象排序,因为不知道大小规则//如果一定要解决在,怎么办?两种方案//1,对象类实现一个Comparable接口,并重写compareTo方法,指定大小排序规则//2,public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data//getset方法
@AllArgsConstructor//有参构造
@NoArgsConstructor//无参构造
public class Teacher implements Comparable<Teacher> {//姓名、年龄、工资private String name;private int age;private double salary;@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +", salary=" + salary +'}'+"\n";}//t2.compareTo (t1)// t2 == this 比较者// t1 == o 被比较者// 规定 1:如果你认为左边大于右边 请返回正整数// 规定 2:如果你认为左边小于右边 请返回负整数// 规定 3:如果你认为左边等于右边 请返回 0// 默认就会升序。@Overridepublic int compareTo(Teacher o) {return this.getAge() - o.getAge();}
}
运行结果:

2,public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;public class SetDemo3 {public static void main(String[] args){//目标:搞清楚TreeSet集合对于自定义对象的排序Set<Teacher> set = new TreeSet<>(new Comparator<Teacher>() {@Overridepublic int compare(Teacher o1, Teacher o2) {
//                if (o1.getSalary() > o2.getSalary())
//                    return 1;
//                else if (o1.getSalary() < o2.getSalary())
//                    return -1;
//                return 0;//                return o1.getSalary() > o2.getSalary() ? -1 : o1.getSalary() < o2.getSalary() ? 1 : 0;return Double.compare(o1.getSalary(), o2.getSalary());}});//排序、不重复、无索引set.add(new Teacher("张三", 28, 3000));set.add(new Teacher("李四", 21, 14000));set.add(new Teacher("小赵", 18, 5000));set.add(new Teacher("小虎", 8, 2000));System.out.println(set);//结论:TreeSet集合默不能给自定义对象排序,因为不知道大小规则//如果一定要解决在,怎么办?两种方案//1,对象类实现一个Comparable接口,并重写compareTo方法,指定大小排序规则//2,public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data//getset方法
@AllArgsConstructor//有参构造
@NoArgsConstructor//无参构造
public class Teacher{//姓名、年龄、工资private String name;private int age;private double salary;@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +", salary=" + salary +'}'+"\n";}
}

运行结果:

三,Map集合:

1,介绍:

public static void main(String[] args) {//目标:认识Map集合的体系特点//1,创建Map集合//HasgMap特点:无序、不重复、无索引,键值对都可以是null,值不做要求(可以重复)// LinkedMap 特点:有序,不重复,无索引,键值对都可以是 null,值不做要求(可以重复)// TreeMap:按照键可排序,不重复,无索引Map<String,Integer> map = new HashMap<>();//多态map.put("洗衣液",40);map.put("洗衣液",55);map.put("水杯",10);map.put("羽毛球拍",20);map.put("游戏机",1000);map.put(null,null);System.out.println(map);//{null=null, 水杯=10, 游戏机=1000, 洗衣液=55, 羽毛球拍=20}
}

2,Map集合的常用功能:

3,keySet、values方法的示例:
public static void main(String[] args) {Map<String,Integer> map = new HashMap<>();//多态map.put("洗衣液",40);map.put("洗衣液",55);map.put("水杯",10);map.put("羽毛球拍",10);map.put("游戏机",1000);map.put(null,null);System.out.println(map);//{null=null, 水杯=10, 游戏机=1000, 洗衣液=55, 羽毛球拍=20}//keySet方法:获取所有的键,放到一个Set集合返回给我们Set<String> keys = map.keySet();for(String key:keys){//通过key获取valueSystem.out.print(key+" ");}System.out.println();//换 行//values方法:获取所有的值,放到一个Collection集合返回给我们Collection<Integer> values = map.values();for(Integer value:values){System.out.print(value+" ");}
}

运行结果:

4,Map的三种遍历方式:

I,第一种(键找值):

示例:

public static void main(String[] args) {//目标:掌握Map集合的遍历方式一:键找值Map<String,Integer> map = new HashMap<>();//多态map.put("洗衣液",40);map.put("洗衣液",55);map.put("水杯",10);map.put("羽毛球拍",10);map.put("游戏机",1000);map.put(null,null);System.out.println(map);//{null=null, 水杯=10, 游戏机=1000, 洗衣液=55, 羽毛球拍=20}// 1、提取Map集合的全部键到一个Set集合中去Set<String> keys = map.keySet();// 2、遍历Set集合,得到每一个键for (String key : keys) {// 3、根据键去找值Integer value = map.get(key);System.out.println(key + "=" + value);}
}

运行结果:

II,第二种(键值对):

示例:

public static void main(String[] args) {//目标:掌握Map集合的遍历方式二:键值对Map<String,Integer> map = new HashMap<>();//多态map.put("洗衣液",40);map.put("洗衣液",55);map.put("水杯",10);map.put("羽毛球拍",10);map.put("游戏机",1000);System.out.println(map);//{null=null, 水杯=10, 游戏机=1000, 洗衣液=55, 羽毛球拍=20}//1,把Map集合转化为Set集合,里面的元素类型都是键值对类型(Map.Entry<String,Integer>)/*** map = {水杯=10, 游戏机=1000, 洗衣液=55, 羽毛球拍=10}* ↓* map.entrySet()* ↓* Set<Map.Entry<String, Integer>> entries = [(嫦娥=28), (铁扇公主=38), (紫霞=31), (女儿国王=31)]*                                                         entry*/Set<Map.Entry<String, Integer>> entries = map.entrySet();for(Map.Entry<String,Integer> entry:entries){//通过entry获取键和值String key = entry.getKey();//键Integer value = entry.getValue();//值System.out.println(key+"="+value);}
}

注:

1,map.entrySet() 方法返回的 Set 集合中,每个元素都是 Map.Entry 接口的实现类对象

2,当我们用一个 Set 类型的变量接收这个返回值时,由于集合中元素的 “接口类型” 是 Map.Entry<K, V>

III,第三种(Lambda表达式):

示例:

public static void main(String[] args) {//目标:掌握Map集合的遍历方式三:Lambda表达式Map<String,Integer> map = new HashMap<>();//多态map.put("洗衣液",55);map.put("水杯",10);map.put("羽毛球拍",10);map.put("游戏机",1000);System.out.println(map);//{水杯=10, 游戏机=1000, 洗衣液=55, 羽毛球拍=20}// 1、直接调用Map集合的forEach方法完成遍历
//    map.forEach(new BiConsumer<String, Integer>() {
//        @Override
//        public void accept(String k, Integer v) {
//            System.out.println(k + "=" + v);
//        }
//    });// Lambda表达式简化:map.forEach((k, v) -> System.out.println(k + "=" + v));}

调用了集合map的forEach方法,里面运用第二种方法,还会回调重写的accept方法

5,HashMap集合的底层原理:

6,LinkedHashMap集合的底层原理:

7,TreeMap集合(指定大小排序规则):

Stream流:

一,认识Stream流:

二,获取Stream流:

示例:

public static void main(String[] args) {// 1、获取集合的Stream流:调用集合提供的stream()方法Collection<String> list = new ArrayList<>();Stream<String> s1 = list.stream();//Collection集合的stream()方法// 2、Map集合,怎么拿Stream流。Map<String, Integer> map = new HashMap<>();// 获取键流,keySet方法:获取所有的键,放到一个Set集合中,并返回Set集合Stream<String> s2 = map.keySet().stream();// 获取值流,values方法:获取所有的值,放到一个Collection集合中,并返回Collection集合Stream<Integer> s3 = map.values().stream();// 获取键值对流,entrySet方法:获取所有的键值对,放到一个Set集合中,并返回Set集合Stream<Map.Entry<String, Integer>> s4 = map.entrySet().stream();// 3、获取数组的流。String[] names = {"张三丰", "张无忌", "张翠山", "张良", "张学友"};// Arrays.stream(T[] array)Stream<String> s5 = Arrays.stream(names);System.out.println(s5.count()); // 5//of方法:参数可以是数组,也可以是多个元素Stream<String> s6 = Stream.of(names);Stream<String> s7 = Stream.of("张三丰", "张无忌", "张翠山", "张良", "张学友");
}

三,Stream流常用的中间方法:

1,使用步骤:
2,常用方法:

示例:

public static void main(String[] args) {// 目标:掌握Stream提供的常用的中间方法,对流上的数据进行处理(返回新流:支持链式编程)List<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若");list.add("赵敏");list.add("张强");list.add("张三丰");list.add("张翠山");// 1、过滤方法,filterlist.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(s -> System.out.println(s));// 2、排序方法, sortedList<Double> scores = new ArrayList<>();scores.add(88.6);scores.add(66.6);scores.add(77.6);scores.add(99.6);scores.stream().sorted().forEach(s -> System.out.println(s)); // 默认是升序。System.out.println("--------------------------------");scores.stream().sorted((s1, s2) -> Double.compare(s2, s1)).forEach(s -> System.out.println(s)); // 降序System.out.println("--------------------------------");scores.stream().sorted((s1, s2) -> Double.compare(s2, s1)).limit(2).forEach(System.out::println); // 只要前2名System.out.println("--------------------------------");scores.stream().sorted((s1, s2) -> Double.compare(s2, s1)).skip(2).forEach(System.out::println); // 跳过前2名System.out.println("--------------------------------");// 如果希望自定义对象能够去重复,重写对象的hashCode和equals方法,才可以去重复!scores.stream().sorted((s1, s2) -> Double.compare(s2, s1)).distinct().forEach(System.out::println); // 去重复// 映射/加工方法:把流上原来的数据拿出来变成新数据又放到流上去。scores.stream().map(s -> "加10分后:" + (s + 10)).forEach(System.out::println);// 合并流:Stream<String> s1 = Stream.of("张三丰", "张无忌", "张翠山", "张良", "张学友");Stream<Integer> s2 = Stream.of(111, 22, 33, 44);Stream<Object> s3 = Stream.concat(s1, s2);System.out.println(s3.count());// 9   //这个新的流元素个数为9(5+4).}

四,终极方法,收集Stream流:

1,终极方法:

示例:

public static void main(String[] args) {// 目标:掌握Stream流的统计,收集操作(终结方法)List<Teacher> teachers = new ArrayList<>();teachers.add(new Teacher("张三", 23, 5000));teachers.add(new Teacher("金毛狮王", 54, 16000));teachers.add(new Teacher("李四", 24, 6000));teachers.add(new Teacher("王五", 25, 7000));teachers.add(new Teacher("白眉鹰王", 66, 108000));teachers.add(new Teacher("陈昆", 42, 48000));teachers.stream().filter(t -> t.getSalary() > 15000).forEach(System.out::println);System.out.println("-------------------------------------------------");long count = teachers.stream().filter(t -> t.getSalary() > 15000).count();System.out.println(count);System.out.println("-------------------------------------------------");// 获取薪水最高的老师对象Optional<Teacher> max = teachers.stream().max((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));Teacher maxTeacher = max.get(); // 获取Optional对象中的元素System.out.println(maxTeacher);Optional<Teacher> min = teachers.stream().min((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));Teacher minTeacher = min.get(); // 获取Optional对象中的元素System.out.println(minTeacher);
}
2,收集Stream流:

http://www.dtcms.com/a/457069.html

相关文章:

  • 鸿蒙 hiperf 制作火焰图
  • 随机变量基础教程
  • 鞋子网站建设策划书北京网站设计多少钱
  • 超越传统:精密蚀刻如何实现±1μm的极致公差
  • 鸿蒙NEXT系列之鸿蒙NDK UI 初探
  • gRPC从0到1系列【25】
  • 冠县网站建设电话wordpress优化打开速度插件
  • Redis中string底层实现原理
  • 百度经验官方网站登录入口常州网站建设方案优化
  • 网站改域名如何做百度优化企业网站营销典型案例
  • Java采用easyexcel组件进行excel表格单元格的自动合并
  • 整体设计 逻辑系统程序 之18 Source 容器(Docker)承载 C/P/D 三式的完整设计与双闭环验证 之2
  • 汽车保险网站简历模板大学生
  • 基于pytest的接口测试
  • 阿里巴巴做网站需要多少钱镇江vi设计
  • 嵌入式Linux(以泰山派无 eMMC 版为例,嘉立创给的Linux镜像有问题!)系统报错磁盘不够但我用的是32G不可能不够怎么解决
  • 开源一个本地AI知识库
  • js哈哈哈哈哈哈哈哈哈哈
  • 做外汇都要看什么网站多元网站建设
  • 一些主要应用和NAT
  • AI编程开发系统028-基于Vue+SpringBoot的宠物领养系统系统(源码+部署说明+演示视频+PPT+lw)
  • MySQL连接池原理与网站数据流动(了解)
  • Hadess入门到实战(8) - 如何管理Go制品
  • 最短路径问题总结
  • 建设银行网站为什么登不上门头设计
  • NX543NX551美光SSD固态闪存NX552NX564
  • 倍增:快速幂
  • 网站关键词快速排名工具网站建设项目可行性分析
  • 开源AI智能名片链动2+1模式S2B2C商城小程序在现代营销运营中的应用与实践
  • 自然语言处理分享系列-词向量空间中的高效表示估计(二)