Java8 Stream收集器collect操作
收集器, 一种通用的、 从流生成复杂值的结构。 只要将它传给 collect 方法, 所有的流就都可以使用它了。
收集器可以做很多事情,例如:计数、分组、归并、求和等。
序号 | 方法 | 含义 |
---|---|---|
1 | Collectors.averageingInt Collectors.averagingLong Collectors.averagingDouble | 平均值 |
2 | Collectors.collectingAndThen | 统计并转换 |
3 | Collectors.counting | 计数 |
4 | Collectors.groupingBy | 分组 |
5 | Collectors.mapping | 替换 |
6 | Collectors.maxBy Collectors.minBy | 最大值、最小值 |
7 | Collectors.partitioningBy | 按Boolean分组 |
8 | Collectors.reducing | 归并 |
9 | Collectors.summarizingInt Collectors.summarizingLong Collectors.summarizingDouble | 获得统计结果对象 |
10 | Collectors.summingInt Collectors.summingLong Collectors.summingDouble | 求和 |
11 | Collectors.toList | 将流转换成list |
12 | Collectors.toSet | 将流转换成set |
13 | Collectors.toCollection | 将流转换成Collection |
14 | Collectors.toMap Collectors.toConcurrentMap | 将流转换成map |
Collectors.averagingInt、Collectors.averagingLong、Collectors.averagingDouble:
统计Stream<T>流中, (根据)每个元素T得到的类型为int/long/double的数值的平均值。
/**
* 统计Stream<T>流中, (根据)每个元素T得到的类型为int/long/double的数值的平均值。
*
* 注:统计结果为Double。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的caveragingLong方法,签名为:
* Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper)
*
* 注:Collectors的caveragingLong方法,签名为:
* Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper)
*
* 注:Collectors的caveragingLong方法,签名为:
* Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper)
*
* 注:当前stream元素类型为T。
*
* 注:由于计算机二进制存数的问题,返回的double值可能存在误差。
*
* 建议:尽量少用此方法,如果非要用的话,建议用在那些对精度要求不高的场景下,且对结果进行舍入。
*/
@Test
public void test27_0() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三").age(18).workStartTimestamp(1L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(24).workStartTimestamp(2L).faceScore(89.2D).build(),
Staff.builder().name("王五").age(45).workStartTimestamp(3L).faceScore(68.6D).build()
);
// Collectors.averagingInt进行统计
Double averageOne = tmpList.parallelStream().collect(
// -> 根据Int值统计出平均值Double的统计器
Collectors.averagingInt(
x -> x == null ? 0 : x.getAge()
)
);
// 输出: 29.0
System.out.println(averageOne);
// Collectors.averagingLong进行统计
Double averageTwo = tmpList.parallelStream().collect(
// -> 根据Long值统计出平均值Double的统计器
Collectors.averagingLong(
x -> x == null ? 0L : x.getWorkStartTimestamp()
)
);
// 输出: 2.0
System.out.println(averageTwo);
// Collectors.averagingDouble进行统计
Double averageThree = tmpList.parallelStream().collect(
// -> 根据Double值统计出平均值Double的统计器
Collectors.averagingDouble(
x -> x == null ? 0D : x.getFaceScore()
)
);
// 输出: 85.90000000000002
// 注:由于计算机二进制存数的问题,返回的double值可能存在误差, 如:这里理
// 论上应返回85.9, 但是实际上返回的是85.90000000000002
System.out.println(averageThree);
}
Collectors.collectingAndThen:
先按照Collectors对Stream<T>流中的元素进行统计(得到R), 再利用Function<R,RR>得到并返回RR。
/**
* 先按照Collectors对Stream<T>流中的元素进行统计(得到R), 再利用Function<R,RR>得到并返回RR。
* 即:对流的元素先Collector<T,A,R> downstream,再对得到的结果进行Function<R,RR> finisher,最后返回RR。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的collectingAndThen方法,签名为:
* Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
* Function<R,RR> finisher)
*
* 注:当前stream类型为T。
*/
@Test
public void test27_1() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三").age(18).workStartTimestamp(1L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(25).workStartTimestamp(2L).faceScore(89.2D).build(),
Staff.builder().name("王五").age(40).workStartTimestamp(3L).faceScore(68.7D).build()
);
// 为便于理解,这里 先编写一个Function<R,RR> finisher
Function<Set<Staff>, Integer> function = Set::size;
// 先Collector<T,A,R> downstream,再Function<R,RR> finisher,最后返回RR。
Integer size = tmpList.parallelStream().collect(
Collectors.collectingAndThen(
Collectors.toSet(),
function
)
);
// 输出: 3
System.out.println(size);
}
Collectors.counting:
对stream中的元素进行计数。
/**
* 对stream中的元素进行计数。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的counting方法,签名为:
* Collector<T, ?, Long> counting()
*
* 注:当前stream类型为T。
*/
@Test
public void test27_2() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三").age(18).workStartTimestamp(1L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(25).workStartTimestamp(2L).faceScore(89.2D).build(),
Staff.builder().name("王五").age(40).workStartTimestamp(3L).faceScore(68.7D).build()
);
@SuppressWarnings("all")
// 对stream中的元素进行计数。 等价于Stream的count()方法。
Long count = tmpList.parallelStream().collect(
Collectors.counting()
);
// 输出: 3
System.out.println(count);
}
Collectors.groupingBy:
对stream中的元素进行分组。
用法一: 先通过classifier,计算每个元素对应的key,然后再通过Collectors的groupingBy方法,按key值分组,得到并返回Map<K, List<T>>。
/**
* 对stream中的元素进行分组:
* 先通过classifier,计算每个元素对应的key,然后再通过Collectors的
* groupingBy方法,按key值分组,得到并返回Map<K, List<T>>
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的重载groupingBy方法,(本次示例的方法的)签名为:
* Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
* 追注:此方法内部调用的实际是groupingBy(classifier, HashMap::new, toList())方法
*
* 注:此方法返回的Map实现是非线程安全的,如果需要返回线程安全的Map实现,可使用(使用方式几乎一致):
* Collector<T, ?, ConcurrentMap<K, List<T>>> groupingByConcurrent(Function<? super T, ? extends K> classifier)
*
* 注: 不论是串行stream,还是并行parallelStream,对于groupingBy(或groupingByConcurrent)本身来说,是线程安全的。
*
* 注:当前stream类型为T。
*
*
*/
@Test
public void test27_3() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三1").age(18).build(),
Staff.builder().name("张三2").age(15).build(),
Staff.builder().name("李四1").age(25).build(),
Staff.builder().name("李四2").age(23).build(),
Staff.builder().name("王五1").age(55).build(),
Staff.builder().name("王五2").age(40).build()
);
// 为便于理解,这里 先编写一个Function<? super T, ? extends K> classifier
// 这个classifier的作用是: 根据元素T,返回其对应的K, 然后Collectors.groupingBy会根据K,
// 将stream中的元素按键值对分组为Map<K, List<T>
Function<Staff, String> function = x -> x.getName() == null ? "" : x.getName().substring(0, 1);
// 使用Collectors.groupingBy,按照(通过Function得到的)key进行分组,得到并返回Map<K, List<T>>
Map<String, List<Staff>> resultMap = tmpList.parallelStream().collect(
Collectors.groupingBy(function)
);
// 输出(为方便观察,本人简单整理了一下输出结果):
// {
// 张=[
// Staff(name=张三1, age=18, staffNo=null, faceScore=null, workStartTimestamp=null),
// Staff(name=张三2, age=15, staffNo=null, faceScore=null, workStartTimestamp=null)
// ],
//
// 王=[
// Staff(name=王五1, age=55, staffNo=null, faceScore=null, workStartTimestamp=null),
// Staff(name=王五2, age=40, staffNo=null, faceScore=null, workStartTimestamp=null)
// ],
//
// 李=[
// Staff(name=李四1, age=25, staffNo=null, faceScore=null, workStartTimestamp=null),
// Staff(name=李四2, age=23, staffNo=null, faceScore=null, workStartTimestamp=null)
// ]
// }
System.out.println(resultMap);
}
用法二: 先通过classifier,计算每个元素对应的key,然后根据key进行分组,然后对每组的元素T进行downstream统计,得到每组的结果D, 最终返回Map<K, D>。
即:先通过classifier得到Map<K, List<T>>,再通过对每个List<T>进行downstream统计,最终得到Map<K, D>。
/**
* 对stream中的元素进行分组:
* 先通过classifier,计算每个元素对应的key,然后根据key进行分组,然后对每组的
* 元素T进行downstream统计,得到每组的结果D, 最终返回Map<K, D>。
* 即:先通过classifier得到Map<K, List<T>>,再通过
* 对每个List<T>进行downstream统计,最终得到Map<K, D>。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的重载groupingBy方法,(本次示例的方法的)签名为:
* Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
* Collector<? super T, A, D> downstream)
* 追注:此方法内部调用的实际是groupingBy(classifier, HashMap::new, downstream)方法
*
* 注:此方法返回的Map实现是非线程安全的,如果需要返回线程安全的Map实现,可使用(使用方式几乎一致):
* Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
* Collector<? super T, A, D> downstream)
*
* 注: 不论是串行stream,还是并行parallelStream,对于groupingBy(或groupingByConcurrent)本身来说,是线程安全的。
*
* 注:当前stream类型为T。
*/
@Test
public void test27_4() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三1").age(18).build(),
Staff.builder().name("张三2").age(15).build(),
Staff.builder().name("张三3").age(11).build(),
Staff.builder().name("李四1").age(25).build(),
Staff.builder().name("李四2").age(23).build(),
Staff.builder().name("王五1").age(55).build(),
Staff.builder().name("王五2").age(40).build()
);
// 为便于理解,这里 先编写一个Function<? super T, ? extends K> classifier
Function<Staff, String> function = x -> x.getName() == null ? "" : x.getName().substring(0, 1);
// 使用Collectors.groupingBy,按照(通过Function得到的)key进行分组并对各组元素进行统计,得到并返回Map<K, D>
Map<String, Long> resultMap = tmpList.parallelStream().collect(
Collectors.groupingBy(function, Collectors.counting())
);
// 输出: {张=3, 王=2, 李=2}
System.out.println(resultMap);
}
用法三: 先通过classifier,计算每个元素对应的key,然后根据key进行分组,然后对每组的元素T进行downstream统计,得到每组的结果D。最终返回Map<K, D>。Map<K, D>即对应Supplier<M> mapFactory中的M,换句话说,返回的Map容器由mapFactory进行提供。
即:先通过classifier得到Map<K, List<T>>,再通过对每个List<T>进行downstream统计,并将K和D放入由mapFactory提供的M中(即:mapFactory提供的Map中),并进行返回。
/**
* 对stream中的元素进行分组:
* 先通过classifier,计算每个元素对应的key,然后根据key进行分组,然后对每组的
* 元素T进行downstream统计,得到每组的结果D。最终返回Map<K, D>。Map<K, D>
* 即对应Supplier<M> mapFactory中的M,换句话说:返回的Map容器由mapFactory进行提供。
* 即:先通过classifier得到Map<K, List<T>>,再通过
* 对每个List<T>进行downstream统计,并将K和D放入由mapFactory提供
* 的M中(即:mapFactory提供的Map中),并进行返回。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的重载groupingBy方法,(本次示例的方法的)签名为:
* Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
* Supplier<M> mapFactory,
* Collector<? super T, A, D> downstream)
* 注:此方法返回的Map实现是非线程安全的,如果需要返回线程安全的Map实现,可使用(使用方式几乎一致):
* Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
* Supplier<M> mapFactory,
* Collector<? super T, A, D> downstream)
*
* 注: 不论是串行stream,还是并行parallelStream,对于groupingBy(或groupingByConcurrent)本身来说,是线程安全的。
*
* 注:当前stream类型为T。
*/
@Test
public void test27_5() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三1").age(18).build(),
Staff.builder().name("张三2").age(15).build(),
Staff.builder().name("张三3").age(11).build(),
Staff.builder().name("李四1").age(25).build(),
Staff.builder().name("李四2").age(23).build(),
Staff.builder().name("王五1").age(55).build(),
Staff.builder().name("王五2").age(40).build()
);
// 为便于理解,这里 先编写一个Function<? super T, ? extends K> classifier
Function<Staff, String> function = x -> x.getName() == null ? "" : x.getName().substring(0, 1);
// Supplier<M> mapFactory
Supplier<TreeMap<String, Long>> mapFactory = TreeMap::new;
// 使用Collectors.groupingBy,按照(通过Function得到的)key进行分组并对各组元素进行统计,得到并返回Map<K, D>
Map<String, Long> resultMap = tmpList.parallelStream().collect(
Collectors.groupingBy(function, mapFactory, Collectors.counting())
);
// 输出: {张=3, 王=2, 李=2}
System.out.println(resultMap);
}
Collectors.joining:
字符串拼接。
用法一:对Stream<String>中的元素直接进行拼接。
/**
* 对Stream<String>中的元素直接进行拼接。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的joining方法,签名为:
* Collector<CharSequence, ?, String> joining()
*
* 注:当前stream类型为T。
*/
@Test
public void test27_6() {
// 数据准备
List<String> tmpList = Lists.newArrayList("A","B","C","D","E");
String resultStr = tmpList.parallelStream().collect(
Collectors.joining()
);
// 输出: ABCDE
System.out.println(resultStr);
}
用法二:对Stream<String>中的元素以delimiter为分隔符进行拼接。
/**
* 对Stream<String>中的元素以delimiter为分隔符进行拼接。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的joining方法,签名为:
* Collector<CharSequence, ?, String> joining(CharSequence delimiter)
*
* 注:当前stream类型为T。
*/
@Test
public void test27_7() {
// 数据准备
List<String> tmpList = Lists.newArrayList("A","B","C","D","E");
String resultStr = tmpList.parallelStream().collect(
Collectors.joining("-")
);
// 输出: A-B-C-D-E
System.out.println(resultStr);
}
用法三:以delimiter为分隔符,以prefix为前缀,以suffix为后缀,对Stream<String>中的元素进行拼接。
/**
* 以delimiter为分隔符,以prefix为前缀,以suffix为后缀,对Stream<String>中的元素进行拼接。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的joining方法,签名为:
* Collector<CharSequence, ?, String> joining(CharSequence delimiter,
* CharSequence prefix,
* CharSequence suffix)
*
* 注:当前stream类型为T。
*/
@Test
public void test27_8() {
// 数据准备
List<String> tmpList = Lists.newArrayList("A","B","C","D","E");
String resultStr = tmpList.parallelStream().collect(
Collectors.joining("-", "[", "]")
);
// 输出: [A-B-C-D-E]
System.out.println(resultStr);
}
Collectors.mapping:
先以mapper将Stream<T>转换为Stream<U>,再用downstream对Stream<U>进行统计。
提示:collect(mapping())能做的事,.map().collect()都能做;我们一般都使用.map().collect(),而不使用collect(mapping())。
/**
* 先以mapper将Stream<T>转换为Stream<U>,再用downstream对Stream<U>进行统计。
*
* 提示:collect(mapping())能做的事,.map().collect()都能做;我们一般都
* 使用.map().collect(),而不使用collect(mapping())。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的mapping方法,签名为:
* Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
* Collector<? super U, A, R> downstream)
*
* 注:当前stream类型为T。
*/
@Test
public void test27_9() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三").age(18).workStartTimestamp(1L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(25).workStartTimestamp(2L).faceScore(89.2D).build(),
Staff.builder().name("王五").age(40).workStartTimestamp(3L).faceScore(68.7D).build()
);
// 为便于理解,这里 先编写一个Function<? super T, ? extends U> mapper
Function<Staff, String> function = Staff::getName;
@SuppressWarnings("all")
String resultStr = tmpList.parallelStream().collect(
Collectors.mapping(
function,
Collectors.joining("&")
)
);
// 输出: 张三&李四&王五
System.out.println(resultStr);
/// 以.map().collect()的方式来实现的话,是这样的:
String resultStr2 = tmpList.parallelStream().map(Staff::getName).collect(Collectors.joining("&"));
// 输出: 张三&李四&王五
System.out.println(resultStr2);
}
Collectors.maxBy、Collectors.minBy:
根据比较器,筛选出Stream<T>中最大、最小的元素。
/**
* 根据比较器,筛选出Stream<T>中最大、最小的元素。
*
* 注:推荐使用.max()、.min()的方式,而非.collect(Collectors.maxBy())、.collect(Collectors.minBy())
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的maxBy方法,签名为:
* Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator)
*
* 注:Collectors的maxBy方法,签名为:
* Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator)
*
* 注:当前stream类型为T。
*/
@Test
@SuppressWarnings("all")
public void test27_10() {
// 数据准备
List<Integer> tmpList = Lists.newArrayList(3, 5, 1, 7, 9);
// 比较器准备
Comparator<Integer> comparator = Comparator.comparingInt(x -> x);
// -> 最大值
// 等价于: tmpList.parallelStream().max(comparator)
Optional<Integer> maxResult = tmpList.parallelStream().collect(
Collectors.maxBy(comparator)
);
// 输出: 9
maxResult.ifPresent(System.out::println);
// -> 最小值
// 等价于: tmpList.parallelStream().min(comparator)
Optional<Integer> minResult = tmpList.parallelStream().collect(
Collectors.minBy(comparator)
);
// 输出: 1
minResult.ifPresent(System.out::println);
}
Collectors.partitioningBy:
(按key为true或false进行)分组。
用法一: 将Stream中的元素,分为两组: predicate通过的分到key为true的组,否者分到key为false的组,最后得到并返回Map<Boolean, List<T>>>。
/**
* 将Stream<T>中的元素,分为两组: predicate通过的分到key为true的组,否者分到key为false的组,
* 最后得到并返回Map<Boolean, List<T>>>。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的partitioningBy方法,签名为:
* Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)
* 追注:此方法与groupingBy方法类似,也是分组。不过此方法是根据predicate将元素分为key为tru/false两组;
* 而groupingBy是根据Function<? super T, ? extends K> classifier来进行的分组。
*
* 注:当前stream类型为T。
*/
@Test
public void test27_11() {
// 数据准备
List<Integer> tmpList = Lists.newArrayList(3, 5, 1, 7, 9);
// 准备一个比较器
Predicate<Integer> predicate = x -> x > 6;
// -> 最大值
Map<Boolean, List<Integer>> resultMap = tmpList.parallelStream().collect(
Collectors.partitioningBy(predicate)
);
// 输出: {false=[3, 5, 1], true=[7, 9]}
System.out.println(resultMap);
}
用法二: 将Stream<T>中的元素,分为两组: predicate通过的分到key为true的组,否者分到key为false的组,然后通过downstream再对每组进行统计(得到统计结果D),最后得到并返回Map<Boolean, D>。
/**
* 将Stream<T>中的元素,分为两组: predicate通过的分到key为true的组,否者分到key为false的组,
* 然后通过downstream再对每组进行统计(得到统计结果D),最后得到并返回Map<Boolean, D>。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的partitioningBy方法,签名为:
* Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
* Collector<? super T, A, D> downstream)
* 追注:此方法与groupingBy方法类似,类比着进行理解即可。
*
* 注:当前stream类型为T。
*/
@Test
public void test27_12() {
// 数据准备
List<Integer> tmpList = Lists.newArrayList(3, 5, 1, 7, 9);
// 准备一个比较器
Predicate<Integer> predicate = x -> x > 6;
// -> 最大值
Map<Boolean, Long> resultMap = tmpList.parallelStream().collect(
Collectors.partitioningBy(
predicate,
Collectors.counting()
)
);
// 输出: {false=3, true=2}
System.out.println(resultMap);
}
Collectors.reducing:
对Stream中的元素进行归并。
提示: 串行流下的reduce与并行流下的reduce可能结果不一样,如果不太熟悉的话,建议使用stream的reduce(),而不使用.stream().collect(Collectors.reducing())。
/**
* 对Stream<T>中的元素进行归并。
* 提示:串行流下的reduce与并行流下的reduce可能结果不一样,如果不太熟悉的话,建议
* 使用stream的reduce(),而不使用.stream().collect(Collectors.reducing())。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的reducing方法,签名为:
* Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op)
*
* 注:当前stream类型为T。
*
* 声明:在stream的collect()方法内部进行reduce的,总共有下述三种方法
* Collector<T,?,Optional<T>> reducing(BinaryOperator<T> op)
* Collector<T,?,T> reducing(T identity, BinaryOperator<T> op)
* Collector<T,?,U> reducing(U identity, Function<? super T,? extends U> mapper, BinaryOperator<U> op),
* 此这里只示例第一种。
*/
@Test
public void test27_13() {
// 数据准备
List<Integer> tmpList = Lists.newArrayList(3, 5, 1, 7, 9);
BinaryOperator<Integer> binaryOperator = Integer::sum;
// -> 进行归并
@SuppressWarnings("all")
Optional<Integer> result = tmpList.stream().collect(
Collectors.reducing(binaryOperator)
);
// 输出: 25
result.ifPresent(System.out::println);
}
Collectors.summarizingInt、Collectors.summarizingLong、Collectors.summarizingDouble:
对Stream<T>中的元素T“对应”的int/long/double值进行统计,并获得一个统计对象;通过此对象可以获得具体的统计信息(如:最大值、最小值、平均值、总和、数量)。
/**
* 对Stream<T>中的元素T“对应”的int/long/double值进行统计,并获得一个统计对象;
* 通过此对象可以获得具体的统计信息(如:最大值、最小值、平均值、总和、数量)。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的summarizingInt方法,签名为:
* Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)
*
* 注:Collectors的summarizingLong方法,签名为:
* Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
*
* 注:Collectors的summarizingDouble方法,签名为:
* Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)
*
* 注:当前stream类型为T。
*
*/
@Test
public void test27_14() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
/// -> summarizingInt示例
// 编写mapper,使用此mapper,能根据Stream<T>中的元素T,获取到对应的int值
ToIntFunction<Staff> intMapper = Staff::getAge;
// 采集数据,获得统计信息 对象
IntSummaryStatistics intResult = tmpList.parallelStream().collect(
Collectors.summarizingInt(intMapper)
);
// 输出: IntSummaryStatistics{count=3, sum=87, min=18, average=29.000000, max=45}
System.out.println(intResult);
/// -> summarizingLong示例
// 编写mapper,使用此mapper,能根据Stream<T>中的元素T,获取到对应的int值
ToLongFunction<Staff> longMapper = Staff::getWorkStartTimestamp;
// 采集数据,获得统计信息 对象
LongSummaryStatistics longResult = tmpList.parallelStream().collect(
Collectors.summarizingLong(longMapper)
);
// 输出: LongSummaryStatistics{count=3, sum=1368, min=123, average=456.000000, max=789}
System.out.println(longResult);
/// -> summarizingDouble示例
// 编写mapper,使用此mapper,能根据Stream<T>中的元素T,获取到对应的double值
ToDoubleFunction<Staff> doubleMapper = Staff::getFaceScore;
// 采集数据,获得统计信息 对象
DoubleSummaryStatistics doubleResult = tmpList.parallelStream().collect(
Collectors.summarizingDouble(doubleMapper)
);
// 输出: DoubleSummaryStatistics{count=3, sum=199.800000, min=33.300000, average=66.600000, max=99.900000}
System.out.println(doubleResult);
}
Collectors.summingInt、Collectors.summingLong、Collectors.summingDouble:
求和。
提示:建议使用.mapToInt().sum(),而不使用.collect(Collectors.summingInt());建议使用.mapToLong().sum(),而不使用.collect(Collectors.summingLong());建议使用.mapToDouble().sum(),而不使用.collect(Collectors.summingDouble())。
/**
* 对Stream<T>中的元素T“对应”的int/long/double值进行求和。
*
* 建议使用.mapToInt().sum(),而不使用.collect(Collectors.summingInt())
* 建议使用.mapToLong().sum(),而不使用.collect(Collectors.summingLong())
* 建议使用.mapToDouble().sum(),而不使用.collect(Collectors.summingDouble())
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的summarizingInt方法,签名为:
* Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper)
*
* 注:Collectors的summarizingLong方法,签名为:
* Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
*
* 注:Collectors的summarizingDouble方法,签名为:
* Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)
*
* 注:当前stream类型为T。
*
*/
@Test
@SuppressWarnings("all")
public void test27_15() {
// 数据准备
List<Staff> tmpList = Lists.newArrayList(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
/// -> summingInt示例
// 编写mapper,使用此mapper,能根据Stream<T>中的元素T,获取到对应的int值
ToIntFunction<Staff> intMapper = Staff::getAge;
// Integer求和
Integer intResult = tmpList.parallelStream().collect(
Collectors.summingInt(intMapper)
);
// 输出: 87
System.out.println(intResult);
/// -> summingLong示例
// 编写mapper,使用此mapper,能根据Stream<T>中的元素T,获取到对应的int值
ToLongFunction<Staff> longMapper = Staff::getWorkStartTimestamp;
// Long求和
Long longResult = tmpList.parallelStream().collect(
Collectors.summingLong(longMapper)
);
// 输出: 1368
System.out.println(longResult);
/// -> summingDouble示例
// 编写mapper,使用此mapper,能根据Stream<T>中的元素T,获取到对应的double值
ToDoubleFunction<Staff> doubleMapper = Staff::getFaceScore;
// Double求和
Double doubleResult = tmpList.parallelStream().collect(
Collectors.summingDouble(doubleMapper)
);
// 输出: 199.8
System.out.println(doubleResult);
}
Collectors.toList:
将Stream<T>转换为一个集合List<T>。
提示:实际上转换成的是ArrayList<T>。
/**
* 将Stream<T>转换为一个集合List<T>。
* 注:实际上转换成的是ArrayList<T>
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的toList方法,签名为:
* Collector<T, ?, List<T>> toList()
*
* 注:当前stream类型为T。
*
*/
@Test
public void test27_16() {
// 数据准备
Stream<Staff> s = Stream.of(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
// 将String<T>转换为集合List<T>
List<Staff> list = s.parallel().collect(
Collectors.toList()
);
// 输出(为方便观察,本人简单整理了一下输出结果):
// [
// Staff(name=张三, age=18, staffNo=null, faceScore=99.9, workStartTimestamp=123),
// Staff(name=李四, age=45, staffNo=null, faceScore=66.6, workStartTimestamp=456),
// Staff(name=王五, age=24, staffNo=null, faceScore=33.3, workStartTimestamp=789)
// ]
System.out.println(list);
}
Collectors.toSet:
将Stream<T>转换为一个集合Set<T>。
提示:实际上转换成的是HashSet<T>。
/**
* 将Stream<T>转换为一个集合Set<T>。
* 注:实际上转换成的是HashSet<T>。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的toSet方法,签名为:
* Collector<T, ?, Set<T>> toSet()
*
* 注:当前stream类型为T。
*
*/
@Test
public void test27_17() {
// 数据准备
Stream<Staff> s = Stream.of(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
// 将String<T>转换为集合List<T>
Set<Staff> set = s.parallel().collect(
Collectors.toSet()
);
// 输出(为方便观察,本人简单整理了一下输出结果):
// [
// Staff(name=张三, age=18, staffNo=null, faceScore=99.9, workStartTimestamp=123),
// Staff(name=李四, age=45, staffNo=null, faceScore=66.6, workStartTimestamp=456),
// Staff(name=王五, age=24, staffNo=null, faceScore=33.3, workStartTimestamp=789)
// ]
System.out.println(set);
}
Collectors.toCollection:
将Stream转换为一个(自定义类型的)集合。
/**
* 将Stream<T>转换为一个(自定义类型的)集合。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的toCollection方法,签名为:
* Collector<T, ?, C> toCollection(Supplier<C> collectionFactory)
*
* 注:当前stream类型为T。
*
*/
@Test
public void test27_18() {
// 数据准备
Stream<Staff> s = Stream.of(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
// 先实现Supplier<C>, Supplier<C>会提供一种集合容器。
Supplier<LinkedList<Staff>> collectionFactory = LinkedList::new;
// 将String<T>转换为集合LinkedList<T>
LinkedList<Staff> linkedList = s.parallel().collect(
Collectors.toCollection(collectionFactory)
);
// 输出(为方便观察,本人简单整理了一下输出结果):
// [
// Staff(name=张三, age=18, staffNo=null, faceScore=99.9, workStartTimestamp=123),
// Staff(name=李四, age=45, staffNo=null, faceScore=66.6, workStartTimestamp=456),
// Staff(name=王五, age=24, staffNo=null, faceScore=33.3, workStartTimestamp=789)
// ]
System.out.println(linkedList);
}
Collectors.toMap、Collectors.toConcurrentMap:
将流转换为Map(或ConcurrentMap)。
特别注意:筛选出来后(,调用Map#merge方法之前,需保证)value值不能为null,否者会报NPE。可详见源码java.util.Map(或其对应子类)的merge方法。
用法一: 将Stream<T>转换为一个Map, 在转换时若发现重复的key,那么会抛出异常。
提示:这里示例的是toMap方法(转换为线程非安全的Map),对应的(转换为线程 安全的ConcurrentMap的)toConcurrentMap方法用法几乎是一样的。
/**
* 将Stream<T>转换为一个Map, 在转换时若发现重复的key,那么会抛出异常。
*
* 提示:这里示例的是toMap方法(转换为线程非安全的Map),对应的(转换为线程
* 安全的ConcurrentMap的)toConcurrentMap方法用法几乎是一样的。
*
* 特别注意:筛选出来后(,调用Map#merge方法之前,需保证)value值不能为null,否者会报NPE。可详见源码java.util.Map(或其对应子类)的merge方法。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的toMap方法,签名为:
* Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
* 追注:此方式的toMap,要求key不能有重复的,否者会出错
* java.lang.IllegalStateException: java.lang.IllegalStateException: Duplicate key...
* 追注:此方法内部调用的其实是:toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
*
* 注:Collectors的toConcurrentMap方法,签名为:
* Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
* 追注:用法与本示例几乎一样,不过toConcurrentMap是线程安全的。
* 追注:此方式的toMap,要求key不能有重复的,否者会出错
* java.lang.IllegalStateException: java.lang.IllegalStateException: Duplicate key...
* 追注:此方法内部调用的其实是:toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new)
*
* 注:当前stream类型为T。
*
*/
@Test
public void test27_19() {
// 数据准备
Stream<Staff> s = Stream.of(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
// 编写一个keyMapper,用于 根据元素T获取对应的key
Function<Staff, String> keyMapper = Staff::getName;
// 编写一个valueMapper,用于 根据元素T获取对应的value
Function<Staff, Integer> valueMapper = Staff::getAge;
// 将Stream<T>转换为Map
Map<String, Integer> resultMap = s.collect(
Collectors.toMap(keyMapper, valueMapper)
);
// 输出: {李四=45, 张三=18, 王五=24}
System.out.println(resultMap);
}
用法二: 将Stream<T>转换为一个Map,在转换时若发现重复的key,那么会根据mergeFunction来决定该key的value是多少。
提示:这里示例的是toMap方法(转换为线程非安全的Map),对应的(转换为线程安全的ConcurrentMap的)toConcurrentMap方法用法几乎是一样的。
/**
* 将Stream<T>转换为一个Map, 在转换时若发现重复的key,那么会根据mergeFunction来决定该key的value是多少。
*
* 提示:这里示例的是toMap方法(转换为线程非安全的Map),对应的(转换为线程
* 安全的ConcurrentMap的)toConcurrentMap方法用法几乎是一样的。
*
* 特别注意:筛选出来后(,调用Map#merge方法之前,需保证)value值不能为null,否者会报NPE。可详见源码java.util.Map(或其对应子类)的merge方法。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的toMap方法,签名为:
* Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)
* 追注:此方法内部调用的其实是:toMap(keyMapper, valueMapper, mergeFunction, HashMap::new)
*
* 注:Collectors的toConcurrentMap方法,签名为:
* Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)
* 追注:用法与本示例几乎一样,不过toConcurrentMap是线程安全的。
* 追注:此方法内部调用的其实是:toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new)
*
* 注:当前stream类型为T。
*
*/
@Test
public void test27_20() {
// 数据准备
Stream<Staff> s = Stream.of(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("张三").age(100).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
// 编写一个keyMapper,用于 根据元素T获取对应的key
Function<Staff, String> keyMapper = Staff::getName;
// 编写一个valueMapper,用于 根据元素T获取对应的value
Function<Staff, Staff> valueMapper = Function.identity();
// 编写一个mergeFunction,用于 处理 key冲突时的逻辑
BinaryOperator<Staff> mergeFunction = (Staff preStaff, Staff nextValue) -> {
// 输出: oldStaff的name是[张三], age是[18]
System.err.println("preStaff的name是[" + preStaff.getName() + "], age是[" + preStaff.getAge() + "]");
// 输出: oldStaff的name是[张三], age是[100]
System.err.println("nextValue的name是[" + nextValue.getName() + "], age是[" + nextValue.getAge() + "]");
return nextValue;
};
// 将Stream<T>转换为Map
Map<String, Staff> resultMap = s.collect(
Collectors.toMap(keyMapper, valueMapper, mergeFunction)
);
// 输出(为方便观察,本人简单整理了一下输出结果):
// {
// 李四=Staff(name=李四, age=45, staffNo=null, faceScore=66.6, workStartTimestamp=456),
// 张三=Staff(name=张三, age=100, staffNo=null, faceScore=99.9, workStartTimestamp=123),
// 王五=Staff(name=王五, age=24, staffNo=null, faceScore=33.3, workStartTimestamp=789)
// }
System.out.println(resultMap);
}
用法三: 将Stream<T>转换为一个(由mapSupplier定义提供的)Map,在转换时若发现重复的key,那么会根据mergeFunction来决定该key的value是多少。
提示:这里示例的是toMap方法(转换为线程非安全的Map),对应的(转换为线程安全的ConcurrentMap的)toConcurrentMap方法用法几乎是一样的。
/**
* 将Stream<T>转换为一个(由mapSupplier定义提供的)Map, 在转换时若发现重复的key,
* 那么会根据mergeFunction来决定该key的value是多少。
*
* 提示:这里示例的是toMap方法(转换为线程非安全的Map),对应的(转换为线程
* 安全的ConcurrentMap的)toConcurrentMap方法用法几乎是一样的。
*
* 特别注意:筛选出来后(,调用Map#merge方法之前,需保证)value值不能为null,否者会报NPE。可详见源码java.util.Map(或其对应子类)的merge方法。
*
* 注:Stream的collect方法,签名为:
* <R, A> R collect(Collector<? super T, A, R> collector)
*
* 注:Collectors的toMap方法,签名为:
* Collector<T,?,M> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)
*
* 注:Collectors的toConcurrentMap方法,签名为:
* Collector<T,?,M> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)
* 追注:用法与本示例几乎一样,不过toConcurrentMap是线程安全的。
*
* 注:当前stream类型为T。
*
*/
@Test
public void test27_21() {
// 数据准备
Stream<Staff> s = Stream.of(
Staff.builder().name("张三").age(18).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("张三").age(100).workStartTimestamp(123L).faceScore(99.9D).build(),
Staff.builder().name("李四").age(45).workStartTimestamp(456L).faceScore(66.6D).build(),
Staff.builder().name("王五").age(24).workStartTimestamp(789L).faceScore(33.3D).build()
);
// 编写一个keyMapper,用于 根据元素T获取对应的key
Function<Staff, String> keyMapper = Staff::getName;
// 编写一个valueMapper,用于 根据元素T获取对应的value
Function<Staff, Integer> valueMapper = Staff::getAge;
// 编写一个mergeFunction,用于 处理 key冲突时的逻辑
BinaryOperator<Integer> mergeFunction = (Integer preValue, Integer nextValue) -> {
// 输出: preValue是: 18
System.err.println("preValue是: " + preValue);
// 输出: nextValue是: 100
System.err.println("nextValue是: " + nextValue);
return nextValue;
};
// Map容器提供者。 .collect(Collectors.toMap())返回的Map, 由此mapSupplier进行提供。
Supplier<LinkedHashMap<String, Integer>> mapSupplier = LinkedHashMap::new;
// 将Stream<T>转换为Map
LinkedHashMap<String, Integer> resultMap = s.collect(
Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapSupplier)
);
// 输出: {张三=100, 李四=45, 王五=24}
System.out.println(resultMap);
}