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 }