参考文章:
写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。
项目上对于list集合操作使用stream流较多,因此专门抽了个时间整理下
这篇博客则侧重于实现方法的展示,主要涉及的中间操作符和终止操作符如下
需要注意的是,stream转换流并不会改动原始对象
操作符分类
(1)中间操作符
filter 过滤操作,把不想要的数据过滤。
sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。
(2)终止操作符
collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors。
count 统计操作,统计最终的数据个数。
findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional。
实例代码如下
1 public class PorblemSolution {
2
3 public static void main(String[] args){
4 List<Student> list = new ArrayList<Student>();
5 list.add(new Student(18,180,'男',"张三"));
6 list.add(new Student(19,170,'女',"李四"));
7 list.add(new Student(19,170,'男',"王五"));
8 list.add(new Student(20,180,'女',"赵六"));
9 list.add(new Student(20,181,'男',"陈七"));
10
11 // stream接口中定义为 Stream<T> filter(Predicate<? super T> predicate);
12 // filter内部参数需为断言语句
13 List<Student> res1 = list.stream().filter(stu->stu.getSex()=='男').collect(Collectors.toList());
14 System.out.println(res1.toString());// [姓名:张三年龄:18身高:180性别:男, 姓名:王五年龄:19身高:170性别:男, 姓名:陈七年龄:20身高:181性别:男]
15
16 Predicate<Student> stuFilter = (stu->stu.getSex()=='女');
17 List<Student> res2 = list.stream().filter(stuFilter).collect(Collectors.toList());
18 System.out.println(res2.toString());// [姓名:李四年龄:19身高:170性别:女, 姓名:赵六年龄:20身高:180性别:女]
19
20
21 // Optional的教程可以看菜鸟教程的这边速通讲解https://www.runoob.com/java/java8-optional-class.html
22 Optional<Student> firstA = res1.stream().filter(stu->stu.getHeight()==180).findFirst();
23 System.out.println(firstA.get());// 姓名:张三年龄:18身高:180性别:男
24
25 Optional<Student> firstAny = res2.stream().filter(stu->stu.getSex()=='女').findAny();
26 System.out.println(firstAny.isPresent() ? firstAny.get():"对象为空");// 姓名:李四年龄:19身高:170性别:女
27
28 int femaleCount = (int) list.stream().filter(stuFilter).count();
29 System.out.println("femaleCount="+femaleCount);// femaleCount=2
30
31 //
32 // 多字段排序,需实现comparator接口
33 list = list.stream().sorted(
34 (stu1, stu2) -> {
35 if (stu1.getAge()==stu2.getAge()) {
36 return stu2.getHeight()-stu1.getHeight();
37 } else {
38 return stu1.getAge()-stu2.getAge();
39 }
40 }).collect(Collectors.toList());
41 System.out.println(list.toString());
42 // [姓名:张三年龄:18身高:180性别:男, 姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男, 姓名:陈七年龄:20身高:181性别:男, 姓名:赵六年龄:20身高:180性别:女]
43
44 // 个性化类通过实现Comparable接口自定义排序规则
45 list = list.stream().sorted().collect(Collectors.toList());
46 System.out.println(list.toString());
47 // [姓名:张三年龄:18身高:180性别:男, 姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男, 姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]
48
49 // 通过lambda表达式定义排序规则(这里以身高为例)
50 list = list.stream().sorted((stu1,stu2)->(stu1.getHeight()-stu2.getHeight())).collect(Collectors.toList());
51 System.out.println(list.toString());
52 // [姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男, 姓名:张三年龄:18身高:180性别:男, 姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]
53
54 // 利用function实现比较器,进而实现多字段比较
55 Function<Student, Integer> byAge = (Student) -> Student.getAge();
56 Function<Student, Integer> byHeight = (Student) -> Student.getHeight();
57 Comparator<Student> mySort = Comparator.comparing(byAge).thenComparing(byHeight);
58 list = list.stream().sorted(mySort).collect(Collectors.toList());
59 System.out.println(list.toString());
60 // [姓名:张三年龄:18身高:180性别:男, 姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男, 姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]
61
62 Map<Integer, List<Student>> ageMap = list.stream().collect(Collectors.groupingBy(Student::getAge));
63 System.out.println(ageMap.toString());
64 // {18=[姓名:张三年龄:18身高:180性别:男], 19=[姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男], 20=[姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]}
65 }
66 }
67
68
69 class Student implements Comparable<Student> {
70 int age;
71 int height;
72 char sex;
73 String name;
74 Student(){}
75 Student(int age,int height,char sex,String name){
76 this.age = age;
77 this.height = height;
78 this.sex = sex;
79 this.name = name;
80 }
81
82 public String toString() {
83 return "姓名:"+name+"年龄:"+age+"身高:"+height+"性别:"+sex;
84
85 }
86
87 @Override
88 public int compareTo(Student stu) {
89 if (this.getAge()==stu.getAge()) {
90 return this.getHeight()-stu.getHeight();
91 } else {
92 return this.getAge()-stu.getAge();
93 }
94 }
95
96 public int getAge() {
97 return age;
98 }
99
100 public int getHeight() {
101 return height;
102 }
103
104 public char getSex() {
105 return sex;
106 }
107
108 public String getName() {
109 return name;
110 }
111
112
113 }
一、filter
stream接口中定义为 Stream<T> filter(Predicate<? super T> predicate);
因此,我们使用filter则需要传入Predicate断言语句,预先编译好的还是lambda表达式都行
(1)利用lambda表达式实现
1 List<Student> res1 = list.stream().filter(stu->stu.getSex()=='男').collect(Collectors.toList());
2 System.out.println(res1.toString());// [姓名:张三年龄:18身高:180性别:男, 姓名:王五年龄:19身高:170性别:男, 姓名:陈七年龄:20身高:181性别:男]
注意最后我们利用collect(Collectors.toList())又重新将stream流转换回list
(2)设定好Predicate后作为参数传入
1 Predicate<Student> stuFilter = (stu->stu.getSex()=='女');
2 List<Student> res2 = list.stream().filter(stuFilter).collect(Collectors.toList());
3 System.out.println(res2.toString());// [姓名:李四年龄:19身高:170性别:女, 姓名:赵六年龄:20身高:180性别:女]
(3)利用Optional实现特定的查找功能(Optional可以预防空指针的出现,注意isPresent用法)
1 // Optional的教程可以看菜鸟教程的这边速通讲解https://www.runoob.com/java/java8-optional-class.html
2 Optional<Student> firstA = res1.stream().filter(stu->stu.getHeight()==180).findFirst();
3 System.out.println(firstA.get());// 姓名:张三年龄:18身高:180性别:男
4
5 Optional<Student> firstAny = res2.stream().filter(stu->stu.getSex()=='女').findAny();
6 System.out.println(firstAny.isPresent() ? firstAny.get():"对象为空");// 姓名:李四年龄:19身高:170性别:女
(4)计数(注意count()的返回是long类型的,使用时需要注意类型转换)
1 int femaleCount = (int) list.stream().filter(stuFilter).count();
2 System.out.println("femaleCount="+femaleCount);// femaleCount=2
二、sorted
stream接口中定义sorted为 Stream<T> sorted();与 Stream<T> sorted(Comparator<? super T> comparator);
要想使用sorted()则需要实现Comparable,否则会报错,要使用Comparator则需要实现自定义的比较器
(1)使用个性化类重写的排序方法排序
1 // 个性化类通过实现Comparable接口自定义排序规则
2 list = list.stream().sorted().collect(Collectors.toList());
3 System.out.println(list.toString());
4 // [姓名:张三年龄:18身高:180性别:男, 姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男, 姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]
(2)使用lambda自定义排序规则
1 // 通过lambda表达式定义排序规则(这里以身高为例)
2 list = list.stream().sorted((stu1,stu2)->(stu1.getHeight()-stu2.getHeight())).collect(Collectors.toList());
3 System.out.println(list.toString());
4 // [姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男, 姓名:张三年龄:18身高:180性别:男, 姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]
(3)利用Comparator.comparing(function)实现比较器,进而实现多字段比较
1 // 利用function实现比较器,进而实现多字段比较
2 Function<Student, Integer> byAge = (Student) -> Student.getAge();
3 Function<Student, Integer> byHeight = (Student) -> Student.getHeight();
4 Comparator<Student> mySort = Comparator.comparing(byAge).thenComparing(byHeight);
5 list = list.stream().sorted(mySort).collect(Collectors.toList());
6 System.out.println(list.toString());
7 // [姓名:张三年龄:18身高:180性别:男, 姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男, 姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]
三、补充
(1)Collectors还提供了分组方法groupingBy来实现类似sql中的group by效果
1 Map<Integer, List<Student>> ageMap = list.stream().collect(Collectors.groupingBy(Student::getAge));
2 System.out.println(ageMap.toString());
3 // {18=[姓名:张三年龄:18身高:180性别:男], 19=[姓名:李四年龄:19身高:170性别:女, 姓名:王五年龄:19身高:170性别:男], 20=[姓名:赵六年龄:20身高:180性别:女, 姓名:陈七年龄:20身高:181性别:男]}
(2)Comparable与Comparator的区别
主要在于使用方法的不同,比如
1 public class PorblemSolution {
2
3 public static void main(String[] args){
4 List<Student> list = new ArrayList<Student>();
5 list.add(new Student(18,180,'男',"张三"));
6 list.add(new Student(19,170,'女',"李四"));
7 list.add(new Student(19,170,'男',"王五"));
8 list.add(new Student(20,180,'女',"赵六"));
9 list.add(new Student(20,181,'男',"陈七"));
10
11 // 使用Comparable
12 list = list.stream().sorted().collect(Collectors.toList());
13
14 // 使用Comparator
15 Collections.sort(list,new Student());
16
17 }
18 }
19
20
21 class Student implements Comparable<Student>,Comparator<Student>{
22 int age;
23 int height;
24 char sex;
25 String name;
26 Student(){}
27 Student(int age,int height,char sex,String name){
28 this.age = age;
29 this.height = height;
30 this.sex = sex;
31 this.name = name;
32 }
33
34 public String toString() {
35 return "姓名:"+name+"年龄:"+age+"身高:"+height+"性别:"+sex;
36
37 }
38
39 @Override
40 public int compareTo(Student stu) {
41 if (this.getAge()==stu.getAge()) {
42 return this.getHeight()-stu.getHeight();
43 } else {
44 return this.getAge()-stu.getAge();
45 }
46 }
47
48 @Override
49 public int compare(Student stu1, Student stu2) {
50 if (stu1.getHeight()==stu2.getHeight()) {
51 return stu1.getAge()-stu2.getAge();
52 } else {
53 return stu1.getHeight()-stu2.getHeight();
54 }
55 }
56
57 public int getAge() {
58 return age;
59 }
60
61 public int getHeight() {
62 return height;
63 }
64
65 public char getSex() {
66 return sex;
67 }
68
69 public String getName() {
70 return name;
71 }
72
73 }