0%

java8-collect方法

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;
}
//getter
//setter
}

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);
//使用Collectors.averagingInt方法求苹果的平均重量
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("-------------------将所有苹果颜色拼接为一个字符串-----------------");
//joining会自动将流中的数据拼接为字符串,在处理时需要保证流中的数据都是字符串
String appleColors = inventory.stream()
.map(Apple::getColor) //将流中的apple转换为apple的颜色
.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 对象的静态工厂方法获取,如果有需要可以查阅手册