## 确定类型 定制collector要实现Collector接口,首先要确定类型 - 待收集元素的类型 - 累加器/accumulate 的类型 - 最终结果的类型 假设要实现这么个收集器: ```java public class GroupingBy implements Collector>,Map>> ``` 类型分别为: - T - Map> - Map> ## 实现收集器的组件 收集器有4个重要的组件,他们都是函数 - supplier - accumulator - combiner - finisher ### supplier supplier 用于创建容器. ```java @Override public Supplier>> supplier() { return ()-> new HashMap<>(); } ``` accumulator是叠加器,相当于reduce里面的第二个参数,用于将下一个内容加入到前面的结果. ```java @Override public BiConsumer>, T> accumulator() { return (accumulator,ele)->{ K key = this.classifier.apply(ele); List tList = accumulator.get(key); if (tList == null){ tList = new ArrayList<>(); } tList.add(ele); accumulator.put(key,tList); }; } ``` 在添加下一个元素之前判断map中有无list 关键的一点是key的获取.由传进来的一个classifier完成,通过classifier 获得key. ### combiner 相当于reduce的参数3,用于将产生的各个容器合并起来 ``` java @Override public BinaryOperator>> combiner() { return (l,r)->{ l.putAll(r); return l; }; } ``` 直接把后一个装到前一个并返回就行 ### finisher 描述返回最终的结果. ``` java @Override public Function>, Map>> finisher() { return accumulator->accumulator; } ``` ## 额外 characteristics 描述数据的返回形式 ```java @Override public Set characteristics() { return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH)); } ``` **相关解释**: ``` /** * Characteristics indicating properties of a {@code Collector}, which can * be used to optimize reduction implementations. */ enum Characteristics { /** * Indicates that this collector is concurrent, meaning that * the result container can support the accumulator function being * called concurrently with the same result container from multiple * threads. * *

If a {@code CONCURRENT} collector is not also {@code UNORDERED}, * then it should only be evaluated concurrently if applied to an * unordered data source. */ CONCURRENT, /** * Indicates that the collection operation does not commit to preserving * the encounter order of input elements. (This might be true if the * result container has no intrinsic order, such as a {@link Set}.) */ UNORDERED, /** * Indicates that the finisher function is the identity function and * can be elided. If set, it must be the case that an unchecked cast * from A to R will succeed. */ IDENTITY_FINISH } ``` ## test ![image](http://ot9zhv7su.bkt.clouddn.com/collector.png)