在介绍 collect 操作中,我们用了 Collectors 中提供的 toList 方法将结果汇总成List,collect 是很常用的操作Collectors中有很多有用的方法值得熟悉一下,其实很多终端方法都是 collect 的快捷写法,如果都不能满足需求我们还可以自己实现一个
转常用集合 // 转list List<String> collect = Stream.of("1", "2", "3").collect(Collectors.toList()); // 转set Set<String> collect = Stream.of("1", "2", "3").collect(Collectors.toSet()); // 转map,key为字符串长度,value为字符串本身 Map<Integer, String> collect = Stream.of("1", "2", "3") .collect(Collectors.toMap(String::length, Function.identity())); // 转并发版map,key为字符串长度,value为字符串本身 Map<Integer, String> collect = Stream.of("1", "2", "3") .collect(Collectors.toConcurrentMap(String::length, Function.identity())); // 转指定类型集合 ArrayList<String> collect = Stream.of("1", "2", "3") .collect(Collectors.toCollection(ArrayList::new)); 拼接字符串 // 拼接成一个字符串 String collect = Stream.of("1", "2", "3").collect(Collectors.joining()); // 拼接成一个字符串,逗号分隔 String collect = Stream.of("1", "2", "3").collect(Collectors.joining(",")); 统计都有对应简化版,一些更加灵活多变的操作可以用Collectors
// 和终端操作中的 max 等价 Stream.of("1", "2", "3").collect(Collectors.maxBy(Comparator.naturalOrder())); // 和终端操作中的 min 等价 Stream.of("1", "2", "3").collect(Collectors.minBy(Comparator.naturalOrder())); // 和终端操作中的 sum 等价 Stream.of("1", "2", "3").collect(Collectors.counting(Integer::valueOf)); // 和数值流终端操作中的 sum 等价 Stream.of("1", "2", "3").collect(Collectors.summingInt(Integer::valueOf)); // 和数值流终端操作中的 average 等价 Stream.of("1", "2", "3").collect(Collectors.averagingInt(Integer::valueOf)); // 和数值流终端操作中的 summaryStatistics 等价 Stream.of("1", "2", "3").collect(Collectors.summarizingInt(Integer::valueOf)); 分组可以和其他收集器方法任意组合
// 以字符串长度分成3组,map的key为长度,value为对应长度字符串list Map<Integer, List<String>> collect = Stream.of("1", "22", "33", "4", "555") .collect(Collectors.groupingBy(String::length)); // 以字符串长度分成3组,map的key为长度,value为对应的元素个数 Map<Integer, Long> collect = Stream.of("1", "22", "33", "4", "555") .collect(Collectors.groupingBy(String::length, Collectors.counting())); // 这个例子没有实际意义,展示我们可以进行二级分组,长度分组完毕,再组内以hash值分组 Map<Integer, Map<Integer, List<String>>> collect = Stream.of("1", "22", "33", "4", "555") .collect(Collectors.groupingBy( String::length, Collectors.groupingBy(String::hashCode) )); 分区分区时特殊的分组,使用方法类似,特殊是通过谓词表达式只能分成两组,true是一组,false是一组
// 以长度大于2为标准分区 Map<Boolean, List<String>> collect = Stream.of("1", "22", "33", "4", "555") .collect(Collectors.partitioningBy(s -> s.length() > 2)); 归约 // 和终端操作 reduce 等价 Stream.of("1", "22", "33", "4", "555") .collect(Collectors.reducing(0, Integer::valueOf, Integer::sum)) 多操作连接 // 把流汇总成list,然后再求出其容量 Integer collect = Stream.of("1", "22", "33", "4", "555") .collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); 自定义有些时候默认的实现有缺陷,或者追求更高的性能我们需要自己实现收集器。只要实现 Collector<T, A , R>接口 中的方法我们就可以获得自己的收集器,其中 T 是元素泛型,A是累加器结果,R是最终返回结果,所有首先我们来看下要实现哪些方法
supplier:提供一个容器 A 装结果
accumulator:累加器,将元素累加进刚才创建的容器
combiner:合并容器的结果
finisher:完成操作,将 A 转为 R 返回
characteristics:是个定义标识的方法
UNORDERED:结果不受流中项目的遍历和累积顺序的影响
CONCURRENT:accumulator函数可以从多个线程同时调用
IDENTITY_FINISH:表示 finisher 没做任何事情,直接返回了累加的结果,也就是A和R相同
public static final Collector<String, List<String>, List<String>> myToList = Collector.of( // supplier: 创建 A(ArrayList) ArrayList::new, // accumulator:把每个元素放入 A 中 (list, el) -> list.add(el), // combiner:如果并行拆分成多个流,直接 addAll 合并 // 如果不想支持并行可以写个空,或抛UnsupportedOperationException异常 (listA, listB) -> { listA.addAll(listB); return listA; }, // finisher:不做任何事情,直接返回 A Function.identity(), // characteristics...:表名 A R 类型相同, 且支持并行流 Collector.Characteristics.IDENTITY_FINISH, Collector.Characteristics.CONCURRENT ); // 自定义收集器转成list List<String> collect = Stream.of("1", "22", "33", "4", "555").collect(myToList);