Stream流 | 总字数: 3.4k | 阅读时长: 16分钟 | 浏览量: | 
 
生成流 
通过集合生成 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 List<String> strList = new  ArrayList <>(); strList.add("a" ); strList.add("b" ); Stream  stream3  =  strList.stream();stream3.forEach(System.out::println); System.out.println("=====================" ); Set<String> strSet = new  HashSet <>(); strSet.add("a" ); strSet.add("b" ); Stream  stream4  =  strSet.stream();stream4.forEach(System.out::println); System.out.println("=====================" ); Map<String, Integer> map = new  HashMap <>(); map.put("a" , 100 ); map.put("b" , 200 ); Stream  stream5  =  map.entrySet().stream();stream5.forEach(System.out::println); System.out.println("=====================" ); 
 
通过数组生成 
1 2 int [] intArr = new  int []{1 , 2 , 3 , 4 , 5 };IntStream  stream  =  Arrays.stream(intArr);
 
该方法生成的流是数值流(IntStream)而不是 Stream,使用数值流可以避免计算过程中拆箱装箱,提高性能
通过值生成 
1 Stream<Integer> stream = Stream.of(1 , 2 , 3 , 4 , 5 ); 
 
通过 Stream 的 of 方法生成流,通过 Stream 的 empty 方法可以生成一个空流
通过文件生成 
1 Stream<String> lines = Files.lines(Paths.get("data.txt" ), Charset.defaultCharset()); 
 
通过 Files.line 方法得到一个流,并且得到的每个流是给定文件中的一行
通过函数生成 
iterate 
 
1 Stream<Integer> stream = Stream.iterate(0 , n -> n + 2 ).limit(5 ); 
 
iterate 方法接受两个参数,第一个为初始值,第二个为进行的函数操作,因为 iterate 生成的流为无限流,通过 limit 方法对流进行了截断,只生成 5 个偶数
generate 
 
1 Stream<Double> stream = Stream.generate(Math::random).limit(5 ); 
 
generate 方法接受一个参数,方法参数类型为 Supplier,由他为流提供值,generate 生成的流也是无限流,因此通过 limit 对流进行了截断
中间操作 
filter 条件筛选 
返回结果生成新的流中只包含满足筛选条件的数据
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 ); Stream<Integer> stream = integerList.stream().filter(i -> i > 3 ); 
 
distinct 去除重复元素 
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 ); Stream<Integer> stream = integerList.stream().distinct(); 
 
limit 返回指定流个数 
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 );  Stream<Integer> stream = integerList.stream().limit(3 ); 
 
通过 limit 方法指定返回流的个数,limit 的参数值必须 >= 0,否则将会抛出异常
skip 跳过流中的元素 
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 ); Stream<Integer> stream = integerList.stream().skip(2 ); 
 
通过 skip 方法跳过流中的元素,skip 的参数值必须 >= 0,否则将会抛出异常
map 流映射 
流映射就是将接受的元素映射成另外一个元素,通过 map 方法可以完成映射
1 2 List<String> stringList = Arrays.asList("Java 8" , "Lambdas" ,  "In" , "Action" ); Stream<Integer> stream = stringList.stream().map(String::length); 
 
常用方法 
mapToDouble
 
mapToInt
 
mapToLong
 
 
使用案例 
当出现相同的 key 时,解决方法:取前面 value 的值,或者取后面放入的 value 值,则覆盖先前的 value 值 
 
1 2 3 4 Map<Long, String> map = userList.stream()         .collect(Collectors.toMap(User::getId, User::getUsername, (v1, v2) -> v1)); Map<Long, String> map = userList.stream()         .collect(Collectors.toMap(User::getId, User::getUsername, (v1, v2) -> v2)); 
 
对相同 key 值的数据进行合并 
 
1 2 Map<Long, Integer> map = itemList.stream().collect(Collectors.toMap(StocksComponentsItem::getStocksId, StocksComponentsItem::getCount, (e1, e2) -> e1 + e2));        
 
获取 TreeMap,根据 key 值进行排序 
 
1 2 3 4 Map<Long, String> treeMap = new  HashMap <>(); TreeMap<Long, String> map = treeMap.entrySet().stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue(),                            (v1, v2) -> v1, TreeMap::new )); 
 
flatMap 流转换 
扁平化映射,将多个 stream 连接成一个 stream,这个操作是针对类似多维数组的,比如集合里面包含集合,相当于降维作用
例如:如果想要从 List < StdCls > 中取出学生列表,需要取出每个班级的学生 List,再 for 循环调用 List.addAll()方法把所有班级的学生 List 到一个新的总和 List 中
1 2 3 4 5 @Data public  class  StdCls  {    private  String clsNo;     private  List<Student> studentList; } 
 
使用 map 映射后会变成 List <List<Student> >,若使用 flatMap 会进行扁平化处理,从而将 List 嵌套 List 用 stream 合并成一个 List
1 2 3 4 List<String> nameList = stdClsList.stream()                         .map(StdCls::getStudentList)                         .flatMap(Collection::stream)                          .map(Student::getName).collect(Collectors.toList()); 
 
sorted 排序 
将流中的元素按照自然排序方式进行排序
sorted():自然排序,流中元素需实现 Comparable 接口 
 
1 2 3 List<String> list = Arrays.asList("aa" , "ff" , "dd" ); list.stream().sorted().forEach(System.out::println); 
 
sorted(Comparator com):定制排序,自定义 Comparator 排序器 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Student  s1  =  new  Student ("aa" , 10 );Student  s2  =  new  Student ("bb" , 20 );Student  s3  =  new  Student ("aa" , 30 );Student  s4  =  new  Student ("dd" , 40 );List<Student> studentList = Arrays.asList(s1, s2, s3, s4);    studentList.stream().sorted(     (o1, o2) -> {         if  (o1.getName().equals(o2.getName())) {         	return  o1.getAge() - o2.getAge();         } else  {         	return  o1.getName().compareTo(o2.getName());         } 	} ).forEach(System.out::println);  
 
peek 消费 
对流中每个元素执行操作,并返回一个新的流,返回的流还是包含原来流中的元素。
如同于 map,能得到流中的每一个元素,但 map 接收的是一个 Function 表达式,有返回值;而 peek 接收的是 Consumer 表达式,没有返回值
1 2 3 4 5 6 7 8 9 Student  s1  =  new  Student ("aa" , 10 );Student  s2  =  new  Student ("bb" , 20 );List<Student> studentList = Arrays.asList(s1, s2);    studentList.stream().peek(o -> o.setAge(100 )).forEach(System.out::println);    Student{name='aa' , age=100 } Student{name='bb' , age=100 } 
 
concat 流合并 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ArrayList<String> list = new  ArrayList <String>(); list.add("心如音" ); list.add("流老蛋" ); list.add("王值" ); list.add("李尔" ); list.add("张新敏" ); list.add("张天坤" ); Stream<String> s1 = list.stream().limit(4 ); Stream<String> s2 = list.stream().skip(2 ); Stream.concat(s1,s2).forEach(System.out::println);  Stream.concat(s1,s2).distinct().forEach(System.out::println); 
 
终端操作 
match 元素匹配 
allMatch 匹配所有 
 
1 2 3 4 5 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); boolean  result  =  integerList.stream().allMatch(i -> i > 3 );if  (result) {    System.out.println("值都大于3" ); } 
 
anyMatch 匹配其中一个 
 
1 2 3 4 5 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); boolean  result  =  integerList.stream().allMatch(i -> i > 3 );if  (result) {    System.out.println("存在大于3的值" ); } 
 
noneMatch 全部不匹配 
 
1 2 3 4 5 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); boolean  result  =  integerList.stream().allMatch(i -> i > 3 );if  (result) {    System.out.println("值都小于3" ); } 
 
count 统计元素个数 
1 2 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Long  result  =  integerList.stream().filter(e -> e > 3 ).count();
 
find 查找元素 
findFirst:查找第一个 
 
1 2 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Optional<Integer> result = integerList.stream().filter(i -> i > 3 ).findFirst(); 
 
findAny:随机查找一个 
 
1 2 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Optional<Integer> result = integerList.stream().filter(i -> i > 3 ).findAny(); 
 
min、max 获取最值 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Optional<Integer> min = integerList.stream().min(Integer::compareTo); System.out.println(min.get()); Optional<Integer> max = integerList.stream().max(Integer::compareTo); System.out.println(max.get()); OptionalInt  min1  =  integerList.stream().mapToInt(e -> e).min();System.out.println(min1.getAsInt()); OptionalInt  max1  =  integerList.stream().mapToInt(e -> e).max();System.out.println(max1.getAsInt()); Optional<Integer> min = menu.stream().map(Dish::getCalories).min(Integer::compareTo); Optional<Integer> max = menu.stream().map(Dish::getCalories).max(Integer::compareTo); OptionalInt  min  =  menu.stream().mapToInt(Dish::getCalories).min();OptionalInt  max  =  menu.stream().mapToInt(Dish::getCalories).max();
 
reduce 元素组合 
把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 String  reduceStr1  =  Stream.of("ma" , "zhi" , "chu" ).reduce("" , String::concat);System.out.println(reduceStr1); String  reduceStr2  =  Stream.of("ma" , "zhi" , "chu" ).reduce("" , (x,y)->x+y);System.out.println(reduceStr2); Integer  total1  =  Stream.of(1 ,2 ,3 ,4 ).reduce(0 , Integer::sum);System.out.println(total1); Integer  total2  =  Stream.of(1 ,2 ,3 ,4 ).reduce(0 , (x, y) -> x +y);System.out.println(total2); Integer  total3  =  Stream.of(1 , 2 , 3 , 4 ).reduce(Integer::sum).get();System.out.println(total3); double  minValue  =  Stream.of(-1.1 , 8.8 , -2.2 , -6.6 ).reduce(Double.MAX_VALUE, Double::min);System.out.println(minValue); Optional<Integer> min = menu.stream().map(Dish::getCalories).reduce(Integer::min); Optional<Integer> max = menu.stream().map(Dish::getCalories).reduce(Integer::max); 
 
求不同值 
summingInt:求和 
sum:求和 
averagingInt:求平均值 
summarizingInt:同时求总和、平均值、最大值、最小值 
 
1 2 3 4 5 6 7 8 9 10 11 int  sum  =  menu.stream().collect(Collectors.summingInt(Dish::getCalories));int  sum  =  menu.stream().map(Dish::getCalories).reduce(0 , Integer::sum);int  sum  =  menu.stream().mapToInt(Dish::getCalories).sum();double  average  =  menu.stream().collect(Collectors.averagingInt(Dish::getCalories));IntSummaryStatistics  intSummaryStatistics  =  menu.stream().collect(Collectors.summarizingInt(Dish::getCalories));double  average  =  intSummaryStatistics.getAverage();  int  min  =  intSummaryStatistics.getMin();  int  max  =  intSummaryStatistics.getMax();  long  sum  =  intSummaryStatistics.getSum();  
 
foreach 元素遍历 
遍历流中的每一个元素,按照指定的方法执行,执行顺序不一定按照流的顺序
1 2 3 4 5 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); integerList.stream().forEach(System.out::println); Stream.of(1 ,2 ,3 ,4 ,5 ,6 ).parallel().forEach(System.out::println); 
 
toArray 返回数组 
1 2 3 String[] strings = Stream.of("ma" , "zhi" , "chu" ).toArray(String[]::new ); System.out.println(Arrays.toString(strings)); 
 
collect 返回集合 
minBy/maxBy 获取最值 
1 2 Optional<Integer> min = menu.stream().map(Dish::getCalories).collect(Collectors.minBy(Integer::compareTo)); Optional<Integer> max = menu.stream().map(Dish::getCalories).collect(Collectors.maxBy(Integer::compareTo)); 
 
toMap 获取属性映射 
1 2 3 4 5 6 7 8 9 10 List<String> strings = menu.stream().map(Dish::getName).collect(Collectors.toList()); Set<String> sets = menu.stream().map(Dish::getName).collect(Collectors.toSet()); Map<Integer, House> houseMap = houses.stream().collect(Collectors.toMap(House::getOwnerid, o -> o)); Map<Integer, House> houseMap1 = houses.stream().collect(Collectors.toMap(House::getOwnerid,  Function.identity())); houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename,(v1,v2)->v2)); houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename,(v1,v2)->v1)); 
 
常用方法:
Collectors.toList() 
Collectors.toMap() 
Collectors.toSet() 
Collectors.toCollection() 
Collectors.toConcurrentMap() 
 
counting 统计元素个数 
1 2 3 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Long  result  =  integerList.stream().count();Long  result  =  integerList.stream().collect(Collectors.counting());
 
joining 拼接流中元素 
1 String  result  =  menu.stream().map(Dish::getName).collect(Collectors.joining(", " ));
 
默认如果不通过 map 方法进行映射处理拼接的 toString 方法返回的字符串,joining 的方法参数为元素的分界符,如果不指定生成的字符串将是一串的
groupingBy 元素分组 
1 2 3 4 5 6 Map<Type, List<Dish>> result = dishList.stream().collect(Collectors.groupingBy(Dish::getType)); Map<String, Map<Integer, List<Dish>>> result = menu.stream().collect(Collectors.groupingBy(Dish::getName,                 Collectors.groupingBy(Dish::getCalories))); 
 
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 ArrayList<GateScanCodeRecord> objects = new  ArrayList <>(); objects.add(new  GateScanCodeRecord ().setMonth("2020-07" ).setDay("2020-07-12" )); objects.add(new  GateScanCodeRecord ().setMonth("2020-06" ).setDay("2020-06-14" )); objects.add(new  GateScanCodeRecord ().setMonth("2020-06" ).setDay("2020-06-12" )); objects.add(new  GateScanCodeRecord ().setMonth("2020-05" ).setDay("2020-05-17" )); objects.add(new  GateScanCodeRecord ().setMonth("2020-05" ).setDay("2020-05-12" )); TreeMap<String, List<GateScanCodeRecord>> collect2 = objects.parallelStream().collect(Collectors.groupingBy(GateScanCodeRecord::getMonth, TreeMap::new , Collectors.toList())); TreeMap<String, List<GateScanCodeRecord>> collect3 =             objects.parallelStream().collect(Collectors.groupingBy(GateScanCodeRecord::getMonth,             () -> new  TreeMap <>((o1, o2) -> Math.toIntExact(Long.parseLong(o2.replaceAll("-" ,"" )) - Long.parseLong(o1.replaceAll("-" ,"" )))),             Collectors.toList())); TreeMap<String, TreeMap<String, List<GateScanCodeRecord>>> collect = objects.stream()             .collect(Collectors.groupingBy(GateScanCodeRecord::getMonth,              () -> new  TreeMap <>((o1, o2) -> Math.toIntExact(Long.parseLong(o2.replaceAll("-" ,"" )) - Long.parseLong(o1.replaceAll("-" ,"" )))),              Collectors.groupingBy(GateScanCodeRecord::getDay,              () -> new  TreeMap <>((o1, o2) -> Math.toIntExact(Long.parseLong(o2.replaceAll("-" ,"" )) - Long.parseLong(o1.replaceAll("-" ,"" )))),              Collectors.toList()))             ); 
 
partitioningBy 元素分区 
1 2 3 4 5 6 Map<Boolean, List<Dish>> result = menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian)); Map<Boolean, List<Dish>> result = menu.stream().collect(Collectors.groupingBy(Dish::isVegetarian)); List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Map<Boolean, List<Integer>> result = integerList.stream().collect(Collectors.partitioningBy(i -> i < 3 )); 
 
groupingBy 和 partitioningBy 区别 
partitioningBy:将一组数据分为两组,key 为 ture 和 false 的两组数据(仅能分为两组) 
groupingBy:将一组数据按照指定的类型分为 N 组,key 为泛型 
 
mapping 获取属性映射集合 
对分组之后的对象集合转换为对象的某个属性的集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public  static  void  main (String[] args)  {    List<Person> personList = new  ArrayList <>();          Person  tom  =  new  Person ("tom" , "男" , 11 );     Person  amy  =  new  Person ("amy" , "女" , 13 );     Person  ali  =  new  Person ("ali" , "男" , 12 );     Person  daming  =  new  Person ("daming" , "男" , 13 );     personList.add(tom);     personList.add(amy);     personList.add(ali);     personList.add(daming);          Map<String, Set<String>> resultMap = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.mapping(Person::getName, Collectors.toSet())));     System.out.println(resultMap.toString()); } 
 
collectingAndThen 归纳处理 
1 2 3 4 String  collect  =  Stream.of("ma" , "zhi" , "chu" ).collect(Collectors.collectingAndThen(Collectors.joining("," ),        String::toUpperCase)); System.out.println(collect);