collect方法 collect 方法是 Stream 中一个很重要的方法,通过这个方法可以将流中的数据格式转换为需要的形式,如,List,Set,Map,求流数据的总数,流中数据某条属性的平均值或者其他值,将流中的字符串拼接为一条字符串等。
收集器是 Stream 用于收集某种形式的数据信息,基本上所有的 Stream 的终端操作都可以使用 collect 方法来实现
collect的定义 collect 方法有两种形式
1 2 3 4 5 6 方法原型1 <R> R collect (Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) ;方法原型2 <R, A> R collect (Collector<? super T, A, R> collector) ;
这里主要使用方法原型 2,这个方法原型接收一个实现了 Collector 接口的对象,Collector 接口有五个抽象方法,幸运的是 java8 封装了一些常用的方法供我们使用,这些常用方法封装在 java.util.stream.Collectors
对象中,这个对象含有多个静态方法,用来返回 Collector 对象
collect 方法示例 Apple.java
1 2 3 4 5 6 7 8 9 10 11 public class Apple { private int weight; private String color; public Apple (int weight, String color) { super (); this .weight = weight; this .color = color; } }
Main.java
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 public class Main { public static void main (String[] args) { List<Apple> inventory = Arrays.asList( new Apple(10 ,"green" ), new Apple(20 ,"red" ), new Apple(12 ,"red" ), new Apple(12 ,"red" ), new Apple(25 ,"green" )); System.out.println("-------------------返回重量最重的苹果----------------" ); Optional<Apple> heaviestApple = inventory.stream().collect(Collectors.maxBy(Comparator.comparing(Apple::getWeight))); System.out.println(heaviestApple); System.out.println("-------------------返回重量最轻的苹果----------------" ); Optional<Apple> lightestApple = inventory.stream().collect(Collectors.minBy(Comparator.comparing(Apple::getWeight))); System.out.println(lightestApple); System.out.println("-------------------返回苹果的总重量----------------" ); int sumInt = inventory.stream().collect(Collectors.summingInt(Apple::getWeight)); System.out.println(sumInt); System.out.println("-------------------求苹果的平均重量-----------------" ); double averageWeight = inventory.stream().collect(Collectors.averagingDouble(Apple::getWeight)); System.out.println(averageWeight); System.out.println("-------------------返回苹果重量的各个数据属性-----------------" ); IntSummaryStatistics intSummartStatistics = inventory.stream().collect(Collectors.summarizingInt(Apple::getWeight)); System.out.println(intSummartStatistics); System.out.println("-------------------将所有苹果颜色拼接为一个字符串-----------------" ); String appleColors = inventory.stream() .map(Apple::getColor) .collect(Collectors.joining(" " )); System.out.println(appleColors); System.out.println("-------------------返回苹果的总数量-----------------" ); Long count = inventory.stream().collect(Collectors.counting()); System.out.println(count); System.out.println("-------------------将苹果按照苹果颜色进行分组----------------" ); Map<String, List<Apple>> appleColorMap = inventory.stream().collect(Collectors.groupingBy(Apple::getColor)); System.out.println(appleColorMap); System.out.println("-------------------将苹果按照苹果颜色和重量进行分组 ----------------" ); System.out.println(inventory.stream().collect(Collectors.groupingBy(Apple::getColor, Collectors.groupingBy(apple -> { if (apple.getWeight() > 10 && apple.getWeight() < 20 ) return "一般" ; else if (apple.getWeight() >= 20 ) return "很重" ; else return "轻" ; })))); System.out.println("-------------------收集每个颜色的苹果有多少个----------------" ); Map<String, Long> colorCount = inventory.stream().collect(Collectors.groupingBy(Apple::getColor,Collectors.counting())); System.out.println(colorCount); System.out.println("-------------------根据苹果颜色进行分区----------------" ); Map<Boolean,List<Apple>> colorPartition = inventory.stream().collect(Collectors.partitioningBy(apple -> apple.getColor().equals("red" ))); System.out.println(colorPartition); System.out.println("-------------------归约操作----------------" ); System.out.println(inventory.stream().collect(Collectors.reducing(0 ,Apple::getWeight,(a,b) -> a + b))); System.out.println(inventory.stream().map(Apple::getWeight).collect(Collectors.reducing((a,b) -> { if (a > b) return a; else return b; }))); System.out.println(inventory.stream().map(Apple::getWeight).collect(Collectors.reducing(100 ,(a,b) -> { if (a > b) return a; else return b; }))); } }
上面代码使用了大多数 Collectors 的方法,还有一些类型的方法,如: averagingDouble,averagingInt,averagingLong 都是相同的。
Collectors 中的方法大致分为分组,分区,容器(返回list,set,map),简单的数值计算和其他
其中分组和分区是有区别的,分区可以看做是分组的特殊形式,分区只会有两个区别满足条件的(true)和不满足条件的(false),不管是分区还是分组,都可以再分,分组是根据返回的条件进行分组
1 Map<String, List<Apple>> appleColorMap = inventory.stream().collect(Collectors.groupingBy(Apple::getColor));
这里就是根据苹果的颜色进行分组,map 中只会有两个主键,red 或者 green。如果将条件改为 Apple::getWeight,那么主键就会有 10,20,12,25,因为有两个重量为 12 的苹果,这两个苹果就会分在一组
1 Map<Boolean,List<Apple>> colorPartition = inventory.stream().collect(Collectors.partitioningBy(apple -> apple.getColor().equals("red" )));
这里根据苹果颜色是不是红色进行分区,只会有两个主键,true 或者 false,true 分区里的苹果都是红色的,false 分区里的值都不是红色的,但是 partitioningBy 里面可以传第二个参数,可以对分区里面再进行收集
(collect方法)操作
容器可以为三种,List,Set,Map 容器,只需要调用 Collectors.toXxxx() 方法就可以将流最后组装成一个容易
简单的数值计算可以直接通过流计算得出,例如 Stream.max() 方法和 Stream.collect(Collectors.maxBy()) 方法是相同的,在某些方面,如
1 IntSummaryStatistics intSummartStatistics = inventory.stream().collect(Collectors.summarizingInt(Apple::getWeight));
可以返回多种数据的不同运算结果,还是很方便的
collect 方法接收一个 Collector 对象,而大多数的 Collector 对象都可以通过 Collectors 对象的静态工厂方法获取,如果有需要可以查阅手册