前言:
相信有很多刚刚入坑程序员的小伙伴被一些代码搞的很头疼,这些代码让我们既感觉到很熟悉,又很陌生的感觉。我们很多刚入行的朋友更习惯于使用for循环或是迭代器去解决一些遍历的问题,但公司里很多老油子喜欢使用Java8新特性Stream流去做,这样可以用更短的代码实现需求,但是对于不熟悉的新手来说,可读性差一些。
1. 为什么有经验的老手更倾向于使用Stream
性能优势,(大数据量)相较于迭代器,速度更快 支持串行与并行处理, 并行处理 更能充分利用CPU的资源 Stream 是一种计算数据的流,它本身不会存储数据 支持函数式编程 代码优雅,让代码更高效,干净,简洁
2. Stream 的使用方式
三步操作:
创建 Stream 中间操作 终止操作
3. Stream 的创建
Stream 的 创建都会依赖于数据源,通常是容器或者数组 Stream 流的创建大致分为4中,最为常用的就是通过集合创建
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.IntStream; import java.util.stream.Stream; public class CreateStreamDemo { public static void main(String[] args) { // 1 通过集合创建Stream也是用的最多的一种形式 List<String> strList = new ArrayList<>(); strList.add( "a" ); strList.add( "b" ); strList.add( "c" ); // 创建串行操作流 Stream<String> stream = strList.stream(); // 创建并行操作流 Stream<String> parallelStream = strList.parallelStream(); // 2 通过数组创建Stream int [] arr = new int []{ 1 , 2 , 3 }; IntStream intStream = Arrays.stream(arr); // 3 通过Stream.of Stream<Integer> integerStream = Stream.of( 1 , 2 , 3 ); Stream<String> stringStream = Stream.of( "a" , "b" , "c" ); // 4 无限流 // 每隔五个数取一个 Stream.iterate( 0 , t -> t + 5 ).forEach(System.out::println); // 迭代 Stream.generate(Math::random).forEach(System.out::println); // 生成 } } |
4. Stream 中间操作
Stream 中间操作,我们最为常用的就是过滤,去重,排序 本章包含我们开发最常用的对对象的去重,和更据对象中的对个属性组合排序
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
import com.zhj.java8.bean.Student; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.TreeSet; import java.util.stream.Stream; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toCollection;
public class MiddleStreamDemo { public static void main(String[] args) { List<Student> students = new ArrayList<>(); students.add( new Student( 1 , "小华" , 23 , 1 )); students.add( new Student( 1 , "小华" , 23 , 2 )); students.add( new Student( 2 , "小米" , 20 , 2 )); students.add( new Student( 3 , "小果" , 30 , 3 )); students.add( new Student( 4 , "小维" , 18 , 2 )); // 过滤 students.stream().filter(stu -> stu.getAge() > 20 ).forEach(System.out::println); // 去重 // 对对象去重是根据引用去重,内容重复并不会去重,除非重写equals和hashCode方法 System.out.println( "----------去重----------" ); System.out.println( "去重1----------" ); students.stream().distinct().forEach(System.out::println); // 对集合中对象某些属性去重,不重写equals和hashCode方法,只能借助其他数据结构来辅助去重 // 单个属性可以stu -> stu.getId() // 多个属性可以stu -> stu.getId() + ";" + stu.getName() System.out.println( "去重2----------" ); ArrayList<Student> distinctList = students.stream().collect( collectingAndThen(toCollection(() -> new TreeSet<>(Comparator测试数据paring(stu -> stu.getId() + ";" + stu.getName()))), ArrayList:: new ) ); distinctList.stream().forEach(System.out::println); // 排序 支持定义排序方式 // sorted 默认使用 自然序排序, 其中的元素必须实现Comparable 接口 System.out.println( "----------排序----------" ); System.out.println( "排序1----------" ); students.stream().sorted().forEach(System.out::println); // sorted(Comparator<? super T> comparator) :我们可以使用lambada 来创建一个Comparator 实例。可以按照升序或着降序来排序元素。 System.out.println( "排序2----------" ); students.stream() .sorted(Comparator测试数据paring(Student::getAge,Comparator.reverseOrder())) // ,Comparator.reverseOrder() 逆序 .forEach(System.out::println); // 创建比较器,通过对比较器内容的定义实现对多个属性进行排序,类似sql中连续的orderBy System.out.println( "排序3----------" ); students.stream().sorted( (s1,s2) -> { if (s1.getAge() == s2.getAge()) { return s1.getSex()测试数据pareTo(s2.getSex()); } else { return -s1.getAge()测试数据pareTo(s2.getAge()); } } ).forEach(System.out::println); System.out.println( "排序4----------" ); Comparator<Student> studentComparator = (s1,s2) -> { Integer age1 = s1.getAge(); Integer age2 = s2.getAge(); if (age1 != age2) return age1 - age2; Integer sex1 = s1.getSex(); Integer sex2 = s2.getSex(); if (sex1 != sex2) return sex2 - sex1; return 0 ; }; students.stream().sorted(studentComparator).forEach(System.out::println); // 截取 截取前三个元素 System.out.println( "----------截取----------" ); students.stream().limit( 3 ).forEach(System.out::println); // 跳过 跳过前3个元素 System.out.println( "----------跳过----------" ); students.stream().skip( 3 ).forEach(System.out::println); // 映射 System.out.println( "----------映射----------" ); System.out.println( "映射Map----------" ); // map接收Lambda,将元素转换其他形式,或者是提取信息,并将其映射成一个新的元素 Stream<Stream<Student>> streamStream1 = students.stream().map(str -> filterStudent(str)); streamStream1.forEach(sm -> sm.forEach(System.out::println)); System.out.println( "映射flatMap----------" ); // map接收Lambda,将流中的每一个元素转换成另一个流,然后把所有流连成一个流 扁平化映射 Stream<Student> studentStream2 = students.stream().flatMap(str -> filterStudent(str)); studentStream2.forEach(System.out::println); // 消费 System.out.println( "----------消费----------" ); students.stream().peek(stu -> stu.setAge( 100 )).forEach(System.out::println); } public static Stream<Student> filterStudent(Student student) { student = new Student(); return Stream.of(student); } } |
Student
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
public class Student implements Comparable<Student> { private Integer id; private String name; private Integer age; private Integer sex; public Student() { } public Student(Integer id, String name, Integer age, Integer sex) { this .id = id; this .name = name; this .age = age; this .sex = sex; } public Integer getId() { return id; } public void setId(Integer id) { this .id = id; } public String getName() { return name; } public void setName(String name) { this .name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this .age = age; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this .sex = sex; } @Override public String toString() { return "Student{" + "id='" + id + '\ '' + ", name='" + name + '\ '' + ", age='" + age + '\ '' + ", sex=" + sex + '}' ; } @Override public int compareTo(Student o) { return this .getAge() - o.getAge(); } } |
5. Stream 终止操作
Stream 的终止操作,最常用的就是讲处理过的数据收集到新的容器中,同时可以实现向Sql聚合函数,分组的一些效果
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
package com.zhj.java8.stream; import com.zhj.java8.bean.Student; import java.util.*; import java.util.stream.Collectors; public class TerminationStreamDemo { public static void main(String[] args) { List<Student> students = new ArrayList<>(); students.add( new Student( 1 , "小华" , 23 , 1 )); students.add( new Student( 2 , "小米" , 20 , 2 )); students.add( new Student( 3 , "小果" , 30 , 3 )); students.add( new Student( 4 , "小维" , 18 , 2 )); students.add( new Student( 5 , "小华" , 23 , 2 )); System.out.println( "--------------------匹配聚合操作--------------------" ); // allMatch:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false boolean allMatch = students.stream().allMatch(stu -> stu.getAge() > 10 ); System.out.println( "全部符合大于10岁条件:" + allMatch); // noneMatch:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false boolean noneMatch = students.stream().noneMatch(stu -> stu.getAge() > 10 ); System.out.println( "全部不符合大于10岁条件:" + noneMatch); // anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false boolean anyMatch = students.stream().anyMatch(stu -> stu.getAge() > 20 ); System.out.println( "含有任意符合大于20岁条件:" + anyMatch); // findFirst:返回流中第一个元素 Student findFirst = students.stream().findFirst().get(); System.out.println( "第一个学生:" + findFirst); // findAny:返回流中的任意元素 Student findAny = students.stream().findAny().get(); System.out.println( "任意一个学生:" + findAny); // count:返回流中元素的总个数 long count = students.stream().count(); System.out.println( "学生总数:" + count); // max:返回流中元素最大值 Student max = students.stream().max(Student::compareTo).get(); System.out.println( "年龄最大学生:" + max); // max:返回流中元素最大值 Student min = students.stream().min(Student::compareTo).get(); System.out.println( "年龄最小学生:" + min); System.out.println( "--------------------规约操作--------------------" ); System.out.println( "学生年龄总和:" + students.stream().map(Student::getAge).reduce(Integer::sum)); System.out.println( "学生年龄最大:" + students.stream().map(Student::getAge).reduce(Integer::max)); System.out.println( "--------------------收集操作--------------------" ); List<Student> list = students.stream().collect(Collectors.toList()); Set<Student> set = students.stream().collect(Collectors.toSet()); Map<Integer, String> map = students.stream().collect(Collectors.toMap(Student::getId, Student::getName)); String joinName = students.stream().map(Student::getName).collect(Collectors.joining( "," , "(" , ")" )); // 总数 students.stream().collect(Collectors.counting()); // 最大年龄 students.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // 年龄和 students.stream().collect(Collectors.summingInt(Student::getAge)); // 平均年龄 students.stream().collect(Collectors.averagingDouble(Student::getAge)); // 信息合集 DoubleSummaryStatistics statistics = students.stream().collect(Collectors.summarizingDouble(Student::getAge)); System.out.println( "count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage()); // 分组 Map<Integer, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getSex)); System.out.println(collect); //多重分组,先根据性别分再根据年龄分 Map<Integer, Map<Integer, List<Student>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.groupingBy(Student::getAge))); //分区 //分成两部分,一部分大于20岁,一部分小于等于20岁 Map<Boolean, List<Student>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 20 )); //规约 Integer allAge = list.stream().map(Student::getAge).collect(Collectors.reducing(Integer::sum)).get(); System.out.println(allAge); } } |
6. Stream 特性
中间操作惰性执行
多个中间操作的话,不会多次循环, 多个转换操作只会在终止操作的时候融合起来,一次循环完成 。
内部迭代 找到符合条件的数据后边的迭代不会进行 流的末端操作只有一次异常: stream has already been operated upon or closed
意思是流已经被关闭了,这是因为当我们使用末端操作之后, 流就被关闭了,无法再次被调用 ,如果我们想重复调用,只能重新打开一个新的流。
到此这篇关于Java8中Stream的使用方式的文章就介绍到这了,更多相关Java8中的Stream内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
原文链接:https://juejin.cn/post/7024371625222995998
查看更多关于Java8中Stream的使用方式的详细内容...