Java8之stream

项目上对于list集合操作使用stream流较多,因此专门抽了个时间整理下

整理思路来源于这边博客,讲解的很清晰[传送门](https://blog.csdn.net/y_k_y/article/details/84633001 "传送门")

这篇博客则侧重于实现方法的展示,主要涉及的中间操作符和终止操作符如下

需要注意的是,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 }
争取早日不再是一只菜鸡
原文地址:https://www.cnblogs.com/jchen104/p/15039849.html