资讯专栏INFORMATION COLUMN

Java8: Stream Collector

Drinkey / 678人阅读

摘要:写在前面本文要介紹的是流收集器在前面的文章中我们都知道如果要收集流数据调用方法即可本文主要是介紹常用的流收集器和自定義流收集器说一说常用的流收集器这里只是简单介绍用法具体是如何实现的我会在下面进行解释是用来连接字符串的流收集器有三个重载方法

写在前面: 本文要介紹的是流收集器.在前面的文章中,我们都知道如果要收集流数据,调用collect方法即可.本文主要是介紹常用的流收集器和自定義流收集器.

1 Common Stream Collectors

说一说常用的流收集器,这里只是简单介绍用法,具体是如何实现的我会在下面进行解释.

1.1 joining

joining是用来连接字符串的流收集器.有三个重载方法.

// method definition
public static Collector joining();
public static Collector joining(CharSequence delimiter);
public static Collector joining(CharSequence delimiter,
                                                         CharSequence prefix,
                                                         CharSequence suffix);
// examples
String res1 = Stream.of("1", "2", "3", "4").collect(joining());             //1234
String res2 = Stream.of("1", "2", "3", "4").collect(joining(","));          //1,2,3,4
String res3 = Stream.of("1", "2", "3", "4").collect(joining(",", "{", "}"));//{1,2,3,4}
1.2 groupingBy

顾名思义,进行分组,也可以多级分组.多级分组是根据上一次分组的结果来进行分组.

// entity
public class Person {
    private String name;
    private int age;
    private double height;
}
// examples
// e1: group by age
Map> groupByAge = list.stream()
.collect(groupingBy(Person::getAge));
// e2: group by age and name
Map>> groupByAgeAndName = list.stream()
.collect(groupingBy(Person::getAge, groupingBy(Person::getName)));
// e3: group by age , name and height
Map>>> groupByAgeAndNameAndHeight = list.stream()
.collect(groupingBy(Person::getAge, groupingBy(Person::getName, groupingBy(Person::getHeight))));
1.3 partition

分区是分组的特殊情况,由一个谓词(返回一个布尔值的函数)作为分类函数.所以返回的Map集合只有两个key,一个true,一个false.

// is age greater than 20
Map> isGT20 = list.stream().collect(partitioningBy(e -> e.getAge() > 20));
// is age greater than 20, and group by age
Map>> isGT20AndGroupByAge = list.stream().collect(partitioningBy(e -> e.getAge() > 20, groupingBy(Person::getAge)));
2 Custom Stream Collector

首先咱们看collect方法的定义:

 R collect(Collector collector);

collect方法接受一个Collector子类对象.我们之前调的toList,groupingBy,partition等等都是Collectors中通过工厂方法创建的流收集器.所以如果我们需要创建自己的流收集器,只需要实现Collector接口即可.先看Collector接口的定义,以及解释其抽象方法的意思:

public interface Collector {
    // 建立新的结果容器.也就是最终流元素进行处理之后的结果是存放在这个容器中的
    Supplier supplier();

    // 将元素添加到结果容器中
    BiConsumer accumulator();

    // 合并两个结果容器,使用parallelStream的时候会调用这个方法
    BinaryOperator combiner();

    // 对结果容器应用最终转换,是累计过程中最后要调的一个函数,作用类似与Stream的map方法
    Function finisher();

    // 返回一个不可变的Characteristic集合,它定义了收集器的行为
    // 尤其是关于流是否可以并行规约,以及使用哪些优化的提示
    Set characteristics();
}
2.1 Example

现在我们需要实现对一个Person对象集合按年龄来分组,实现代码如下:

// define a custom collector
public class MyGrouping implements Collector>, Map>> {
    @Override
    public Supplier>> supplier() {
        return HashMap::new;
    }

    @Override
    public BiConsumer>, Person> accumulator() {
        return (map, p) -> {
            ArrayList list;
            if ((list = map.get(p.getAge())) != null) {
                list.add(p);
            } else {
                list = new ArrayList<>();
                list.add(p);
                map.put(p.getAge(), list);
            }
        };
    }

    @Override
    public BinaryOperator>> combiner() {
        return (m1, m2) -> Stream.of(m1, m2)
                .map(Map::entrySet)
                .flatMap(Collection::stream)
                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> {
                    e1.addAll(e2);
                    return e1;
                }));
    }

    @Override
    public Function>, Map>> finisher() {
        return Function.identity();
    }

    @Override
    public Set characteristics() {
        return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT));
    }
}

// how to use
Map> customGroupByAge = list.stream().collect(new MyGrouping());
3 Summary

collect是一个终端操作,接受一个收集器对象

收集器可以高效地复合起来,进行多级分组,分区和归约

可以实现Collector接口来实现自己的收集器

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70644.html

相关文章

  • Java8 collector接口的定制实现

    摘要:写这个文章其实主要是因为刚有个童鞋问了个问题正写的带劲安利的实现方式,结果还没写完无意发现问题被关闭了哎都写了一半了又不想放弃,就干脆写成文章问题主要就是把集合里的数据按照一定大小顺序平均分成若干组的问题,看起来挺简单的,不过我开始看到就想 写这个文章其实主要是因为刚有个童鞋问了个问题https://segmentfault.com/q/10...正写的带劲安利Java8的实现方式,结...

    zhangwang 评论0 收藏0
  • Stream流与Lambda表达式(四) 自定义收集器

    摘要:一自定义收集器陈杨将集合转换为集合存放相同元素二自定义收集器陈杨将学生对象按照存放从中间容器数据类型转换为结果类型数据类型一致若不一致抛出类型转换异常对中间容器数据结果类型进行强制类型转换多个线程同时操作同一个容器并行多线 一、自定义SetCustomCollector收集器 package com.java.design.Stream.CustomCollector; impor...

    wind5o 评论0 收藏0
  • Stream流与Lambda表达式(二) Stream收集器 Collector接口

    摘要:一收集器接口陈杨收集器接口汇聚操作的元素类型即流中元素类型汇聚操作的可变累积类型汇聚操作的结果类型接口一种可变汇聚操作将输入元素累积到可变结果容器中在处理完所有输入元素后可以选择将累积的结果转换为最终表示可选操作归约操作 一、Stream收集器 Collector接口 package com.java.design.java8.Stream; import com.java.desi...

    or0fun 评论0 收藏0
  • Java8实战》-第六章读书笔记(用流收集数据-01)

    摘要:收集器用作高级归约刚刚的结论又引出了优秀的函数式设计的另一个好处更易复合和重用。更具体地说,对流调用方法将对流中的元素触发一个归约操作由来参数化。另一个常见的返回单个值的归约操作是对流中对象的一个数值字段求和。 用流收集数据 我们在前一章中学到,流可以用类似于数据库的操作帮助你处理集合。你可以把Java 8的流看作花哨又懒惰的数据集迭代器。它们支持两种类型的操作:中间操作(如 filt...

    EscapedDog 评论0 收藏0
  • Java 8 数据流教程

    摘要:数据流教程原文译者飞龙协议这个示例驱动的教程是数据流的深入总结。但是的数据流是完全不同的东西。数据流是单体,并且在函数式编程中起到重要作用。列表上的所有流式操作请见数据流的。基本的数据流使用特殊的表达式,例如,而不是,而不是。 Java 8 数据流教程 原文:Java 8 Stream Tutorial 译者:飞龙 协议:CC BY-NC-SA 4.0 这个示例驱动的教程是J...

    XUI 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<