java stream中Collectors的用法

简介

在java stream中,我们通常需要将处理后的stream转换成集合类,这个时候就需要用到stream.collect方法。collect方法需要传入一个Collector类型,要实现Collector还是很麻烦的,需要实现好几个接口。

于是java提供了更简单的Collectors工具类来方便我们构建Collector。

Collectorsjava.util.stream包下的一个工具类,其中各个方法的返回值可以作为java.util.stream.Stream#collect的入参,实现对队列的各种操作,包括:分组、聚合等。

聚合、分组

聚合元素:toList、toSet、toCollection

这几个函数比较简单,是将聚合之后的元素,重新封装到队列中,然后返回。比如,得到所有Student的 ID 列表,只需要根据需要的结果类型使用不同的方法即可:

// List: [1, 2, 3]final List<String> idList = students.stream().map(Student::getId).collect(Collectors.toList());// Set: [1, 2, 3]final Set<String> idSet = students.stream().map(Student::getId).collect(Collectors.toSet());// TreeSet: [1, 2, 3]final Collection<String> idTreeSet = students.stream().map(Student::getId).collect(Collectors.toCollection(TreeSet::new));

注意:toList方法返回的是List子类,toSet返回的是Set子类,toCollection返回的是Collection子类。我们都知道,Collection的子类包括ListSet等众多子类,所以toCollection更加灵活。

聚合元素:toMap、toConcurrentMap

这两个方法的作用是将聚合元素,重新组装为Map结构,也就是 k-v 结构。两者用法一样,区别是toMap返回的是MaptoConcurrentMap返回ConcurrentMap,也就是说,toConcurrentMap返回的是线程安全的 Map 结构。

比如,我们需要聚合Student的 id:

// {1=Student(id=1, name=张三, birthday=2009-01-01, age=12, score=12.123), 2=Student(id=2, name=李四, birthday=2010-02-02, age=11, score=22.123), 3=Student(id=3, name=王五, birthday=2011-03-03, age=10, score=32.123)}final Map<String, Student> map11 = students.stream()    .collect(Collectors.toMap(Student::getId, Function.identity()));

但是,如果 id 有重复的,会抛出java.lang.IllegalStateException: Duplicate key异常,所以,为了保险起见,我们需要借助toMap另一个重载方法:

// {1=Student(id=1, name=张三, birthday=2009-01-01, age=12, score=12.123), 2=Student(id=2, name=李四, birthday=2010-02-02, age=11, score=22.123), 3=Student(id=3, name=王五, birthday=2011-03-03, age=10, score=32.123)}final Map<String, Student> map2 = students.stream()    .collect(Collectors.toMap(Student::getId, Function.identity(), (x, y) -> x));

可以看到,toMap有不同的重载方法,可以实现比较复杂的逻辑。比如,我们需要得到根据 id 分组的Student的姓名:

// {1=张三, 2=李四, 3=王五}final Map<String, String> map3 = students.stream()    .collect(Collectors.toMap(Student::getId, Student::getName, (x, y) -> x));

比如,我们需要得到相同年龄得分最高的Student对象集合:

// {10=Student(id=3, name=王五, birthday=2011-03-03, age=10, score=32.123), 11=Student(id=2, name=李四, birthday=2010-02-02, age=11, score=22.123), 12=Student(id=1, name=张三, birthday=2009-01-01, age=12, score=12.123)}final Map<Integer, Student> map5 = students.stream()    .collect(Collectors.toMap(Student::getAge, Function.identity(), BinaryOperator.maxBy(Comparator.comparing(Student::getScore))));

所以,toMap可玩性很高。

分组:groupingBy、groupingByConcurrent

groupingBytoMap都是将聚合元素进行分组,区别是,toMap结果是 1:1 的 k-v 结构,groupingBy的结果是 1:n 的 k-v 结构。

操作后聚合:mapping

mapping是先通过Function函数处理数据,然后通过Collector方法聚合元素。比如,获取获取students的姓名列表:

// [张三, 李四, 王五]students.stream()        .collect(Collectors.mapping(Student::getName, Collectors.toList()));

这种计算与java.util.stream.Stream#map方式类似:

// [张三, 李四, 王五]students.stream()        .map(Student::getName)        .collect(Collectors.toList());

从这点上看,还是通过java.util.stream.Stream#map更清晰一些。

聚合后操作:reducing

reducing提供了 3 个重载方法:

  • public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op):直接通过BinaryOperator操作,返回值是Optional

  • public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op):预定默认值,然后通过BinaryOperator操作

  • public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op):预定默认值,通过Function操作元素,然后通过BinaryOperator操作

比如,计算所有students的得分总数:

// Optional[66.369],注意返回类型是Optionalstudents.stream()        .map(Student::getScore)        .collect(Collectors.reducing(Double::sum));// 66.369students.stream()        .map(Student::getScore)        .collect(Collectors.reducing(0.0, Double::sum));// 66.369students.stream()        .collect(Collectors.reducing(0.0, Student::getScore, Double::sum));

mappingreducing的操作与java.util.stream.Stream#reduce方式类似:

 

一文掌握 Java8 Stream 中 Collectors 的 24 个操作_Java_看山_InfoQ写作社区

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值