Java8中Collectors详解

初始化数据

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Student {
    /** 姓名 */
    private String name;
    /** 总分 */
    private int totalScore;
    /** 是否本地人 */
    private boolean local;
    /** 年级 */
    private GradeType gradeType;

    public enum GradeType {ONE,TWO,THREE}

}
List<Student> menu = Arrays.asList(
                new Student("刘一", 721, true, Student.GradeType.THREE),
                new Student("陈二", 637, true, Student.GradeType.THREE),
                new Student("张三", 666, true, Student.GradeType.THREE),
                new Student("李四", 531, true, Student.GradeType.TWO),
                new Student("王五", 483, false, Student.GradeType.THREE),
                new Student("赵六", 367, true, Student.GradeType.THREE),
                new Student("孙七", 499, false, Student.GradeType.ONE));

1.统计平均数(averagingDouble)

averagingDouble方法返回一个Collector收集器,它生成应用于输入元素的double值函数的算术平均值。如果没有元素,则结果为0。

示例:统计所有学生的平均总成绩

Double averagingDouble = menu.stream().collect(Collectors.averagingDouble(Student::getTotalScore));
        Optional.of(averagingDouble).ifPresent(System.out::println);
        
// 557.7142857142857

2.Collector收集器转换(collectingAndThen)

collectingAndThen方法调整Collector收集器以执行其它的结束转换。例如,可以调整toList()收集器,以始终生成一个不可变的列表

以指定字符串list - count输出所有学生的总数

String collect = menu.stream().collect(Collectors.collectingAndThen(Collectors.counting(), a -> "list - count" + a));
System.out.println(collect);

// list -count7

3.输入元素的数量(counting)

counting方法返回一个Collector收集器接受T类型的元素,用于计算输入元素的数量。如果没有元素,则结果为0。

示例:统计所有学生人数

Optional.of(menu.stream().collect(Collectors.counting())).ifPresent(System.out::println);

// 7

4.分组(groupingBy)

4.1 groupingBy(Function)

groupingBy(Function)方法返回一个Collector收集器对T类型的输入元素执行"group by"操作,根据分类函数对元素进行分组,并将结果返回到Map。

分类函数将元素映射到某些键类型K。收集器生成一个Map<K, List<T>>,其键是将分类函数应用于输入元素得到的值,其对应值为List,其中包含映射到分类函数下关联键的输入元素。
无法保证返回的Map或List对象的类型,可变性,可序列化或线程安全性。

注意: 返回的Collector收集器不是并发的。对于并行流管道,combiner函数通过将键从一个映射合并到另一个映射来操作,这可能是一个昂贵的操作。如果不需要保留元素出现在生成的Map收集器中的顺序,则使用groupingByConcurrent(Function)可以提供更好的并行性能。

示例:统计各个年级的学生信息

    Map<Student.GradeType, List<Student>> collect = menu.stream()
        .collect(Collectors.groupingBy(Student::getGradeType));

    Optional.ofNullable(collect).ifPresent(System.out::println);
    
// {TWO=[Student{name='李四', totalScore=531, local=true, gradeType=TWO}], THREE=[Student{name='刘一', totalScore=721, local=true, gradeType=THREE}, Student{name='陈二', totalScore=637, local=true, gradeType=THREE}, Student{name='张三', totalScore=666, local=true, gradeType=THREE}, Student{name='王五', totalScore=483, local=false, gradeType=THREE}, Student{name='赵六', totalScore=367, local=true, gradeType=THREE}], ONE=[Student{name='孙七', totalScore=499, local=false, gradeType=ONE}]}

4.2 groupingBy(Function, Collector)

groupingBy(Function, Collector)方法返回一个Collector收集器,对T类型的输入元素执行级联"group by"操作,根据分类函数对元素进行分组,然后使用指定的下游Collector收集器对与给定键关联的值执行缩减操作。

分类函数将元素映射到某些键类型K。下游收集器对T类型的元素进行操作,并生成D类型的结果。产生收集器生成Map<K, D>。
返回的Map的类型,可变性,可序列化或线程安全性无法保证。

注意: 返回的Collector收集器不是并发的。对于并行流管道,combiner函数通过将键从一个映射合并到另一个映射来操作,这可能是一个昂贵的操作。如果不需要保留向下游收集器提供元素的顺序,则使用groupingByConcurrent(Function, Collector)可以提供更好的并行性能。

示例:统计各个年级的学生人数

Optional.of(menu.stream()
    	.collect(Collectors.groupingBy(Student::getGradeType, Collectors.counting())))
        .ifPresent(System.out::println);

// {THREE=5, ONE=1, TWO=1}

4.3 groupingBy(Function, Supplier, Collector)

groupingBy(Function, Supplier, Collector)方法返回一个Collector收集器,对T类型的输入元素执行级联"group by"操作,根据分类函数对元素进行分组,然后使用指定的下游Collector收集器对与给定键关联的值执行缩减操作。收集器生成的Map是使用提供的工厂函数创建的

分类函数将元素映射到某些键类型K。下游收集器对T类型的元素进行操作,并生成D类型的结果。产生收集器生成Map<K, D>。

注意: 返回的Collector收集器不是并发的。对于并行流管道,combiner函数通过将键从一个映射合并到另一个映射来操作,这可能是一个昂贵的操作。如果不需要保留向下游收集器提供元素的顺序,则使用groupingByConcurrent(Function, Supplier, Collector)可以提供更好的并行性能。

示例:统计各个年级的平均成绩,并有序输出

    Map<Student.GradeType, Double> map = menu.stream()
        .collect(Collectors.groupingBy(
            Student::getGradeType,
            TreeMap::new,
            Collectors.averagingInt(Student::getTotalScore)));

    Optional.of(map.getClass()).ifPresent(System.out::println);
    Optional.of(map).ifPresent(System.out::println);
    
// class java.util.TreeMap
// {ONE=499.0, TWO=531.0, THREE=574.8}

TreeMap 有序的,否则默认顺序

5. 并发分组(groupingByConcurrent)

5.1 groupingByConcurrent(Function)

groupingByConcurrent(Function)方法返回一个并发Collector收集器对T类型的输入元素执行"group by"操作,根据分类函数对元素进行分组

这是一个Collector.Characteristics#CONCURRENT并发和Collector.Characteristics#UNORDERED无序收集器。
分类函数将元素映射到某些键类型K。收集器生成一个ConcurrentMap<K, List>,其键是将分类函数应用于输入元素得到的值,其对应值为List,其中包含映射到分类函数下关联键的输入元素。
无法保证返回的Map或List对象的类型,可变性或可序列化,或者返回的List对象的线程安全性。

5.2 groupingByConcurrent(Function, Collector)

groupingByConcurrent(Function, Collector)方法返回一个并发Collector收集器,对T类型的输入元素执行级联"group by"操作,根据分类函数对元素进行分组,然后使用指定的下游Collector收集器对与给定键关联的值执行缩减操作。

这是一个Collector.Characteristics#CONCURRENT并发和Collector.Characteristics#UNORDERED无序收集器。

分类函数将元素映射到某些键类型K。下游收集器对T类型的元素进行操作,并生成D类型的结果。产生收集器生成Map<K, D>。

5.3 groupingByConcurrent(Function, Supplier, Collector)

groupingByConcurrent(Function, Supplier, Collector)方法返回一个并行Collector收集器,对T类型的输入元素执行级联"group by"操作,根据分类函数对元素进行分组,然后使用指定的下游Collector收集器对与给定键关联的值执行缩减操作。收集器生成的ConcurrentMap是使用提供的工厂函数创建的。

这是一个Collector.Characteristics#CONCURRENT并发和Collector.Characteristics#UNORDERED无序收集器。

分类函数将元素映射到某些键类型K。下游收集器对T类型的元素进行操作,并生成D类型的结果。产生收集器生成Map<K, D>。

6.字符串拼接(joining)

6.1 joining()

joining()方法返回一个Collector收集器,它按遇见顺序将输入元素连接成String。

示例:将所有学生的姓名连接成字符串

 Optional.of(menu.stream().map(Student::getName).collect(Collectors.joining()))
        .ifPresent(System.out::println);
  
 // 刘一陈二张三李四王五赵六孙七

6.2 joining(delimiter)

joining(delimiter)方法返回一个Collector收集器,它以遇见顺序连接由指定分隔符分隔的输入元素。

示例:将所有学生的姓名以","分隔连接成字符串

Optional.of(menu.stream().map(Student::getName).collect(Collectors.joining(",")))
        .ifPresent(System.out::println);

// 刘一,陈二,张三,李四,王五,赵六,孙七

6.3 joining(delimiter, prefix, suffix)

joining(delimiter, prefix, suffix)方法返回一个Collector收集器,它以遇见顺序将由指定分隔符分隔的输入元素与指定的前缀和后缀连接起来。

示例:将所有学生的姓名以","分隔,以Names[为前缀,]为后缀连接成字符串

 Optional.of(menu.stream().map(Student::getName).collect(Collectors.joining(",", "Names[", "]")))
        .ifPresent(System.out::println);
        
// Names[刘一,陈二,张三,李四,王五,赵六,孙七]

7. 映射(mapping)

mapping方法通过在累积之前将映射函数应用于每个输入元素,将Collector收集器接受U类型的元素调整为一个接受T类型的元素。

示例:将所有学生的姓名以","分隔连接成字符串

Optional.of(menu.stream().collect(Collectors.mapping(Student::getName, Collectors.joining(","))))
        .ifPresent(System.out::println);

// 刘一,陈二,张三,李四,王五,赵六,孙七

8. 取最大值(maxBy)

maxBy方法返回一个Collector收集器,它根据给定的Comparator比较器生成最大元素,描述为Optional。

示例:列出所有学生中成绩最高的学生信息

menu.stream().collect(Collectors.maxBy(Comparator.comparingInt(Student::getTotalScore)))
        .ifPresent(System.out::println);

// Student{name='刘一', totalScore=721, local=true, gradeType=THREE}

9. 取最小值(minBy)

minBy方法返回一个Collector收集器,它根据给定的Comparator比较器生成最小元素,描述为Optional。

示例:列出所有学生中成绩最低的学生信息

menu.stream().collect(Collectors.minBy(Comparator.comparingInt(Student::getTotalScore)))
        .ifPresent(System.out::println);

// Student{name='赵六', totalScore=367, local=true, gradeType=THREE}

10. 返回map类型(partitioningBy)

10.1 partitioningBy(Predicate)

partitioningBy(Predicate)方法返回一个Collector收集器,它根据Predicate对输入元素进行分区,并将它们组织成Map<Boolean, List>。

返回的Map的类型,可变性,可序列化或线程安全性无法保证。

示例:列出所有学生中本地和非本地学生信息

Map<Boolean, List<Student>> collect = menu.stream()
    	.collect(Collectors.partitioningBy(Student::isLocal));
    Optional.of(collect).ifPresent(System.out::println);
    
// {false=[Student{name='王五', totalScore=483, local=false, gradeType=THREE}, Student{name='孙七', totalScore=499, local=false, gradeType=ONE}], true=[Student{name='刘一', totalScore=721, local=true, gradeType=THREE}, Student{name='陈二', totalScore=637, local=true, gradeType=THREE}, Student{name='张三', totalScore=666, local=true, gradeType=THREE}, Student{name='李四', totalScore=531, local=true, gradeType=TWO}, Student{name='赵六', totalScore=367, local=true, gradeType=THREE}]}

10.2 partitioningBy(Predicate, Collector)

partitioningBy(Predicate, Collector)方法返回一个Collector收集器,它根据Predicate对输入元素进行分区,根据另一个Collector收集器减少每个分区中的值,并将它们组织成Map<Boolean, D>,其值是下游减少的结果。

返回的Map的类型,可变性,可序列化或线程安全性无法保证。

示例:列出所有学生中本地和非本地学生的平均总成绩

Map<Boolean, Double> collect = menu.stream()
        .collect(Collectors.partitioningBy(
        			Student::isLocal, 
        			Collectors.averagingInt(Student::getTotalScore)));
    Optional.of(collect).ifPresent(System.out::println);

// {false=491.0, true=584.4}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值