Java 8的Stream的Collect方法用于收集处理过的“流”,将“流”转成其他对象。Collect方法接收一个Collector接口实现,除了Java API中的Collectors工厂提供的toList、toSet、groupingBy、partitionBy等实现以外,还可以通过实现Collector方法自定义收集器。
和Collectors.toList()方法相同效果的自定义实现:
/**
* Collector<T,A,R>
* T是流中要收集的类型
* A是累加器的类型
* R是收集操作得到的类型(不一定和A相同)
*/
public class ToListCollector<T> implements Collector<T,List<T>,List<T>> {
@Override
//supplier方法提供一个空的累加器,用于数据处理过程中的收集
public Supplier<List<T>> supplier() {
return ArrayList::new;
}
@Override
//accumulator方法提供归约操作,即数据收集的具体操作
public BiConsumer<List<T>, T> accumulator() {
return List::add;
}
@Override
//combiner方法提供合并并行处理的结果集的操作
public BinaryOperator<List<T>> combiner() {
return (list1, list2) -> {
list1.addAll(list2);
return list1;
};
}
@Override
//finisher提供对结果容器的最终转化,即从A->R
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}
@Override
//characteristics用于设定优化参数,参数有:UNORDERED、CONCURRENT、IDENTITY_FINISH
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Characteristics.CONCURRENT,Characteristics.IDENTITY_FINISH));
}
}
自定义收集器实现将前n个自然数按质数和非质数分区:
public class PrimeNumbersCollector implements Collector<Integer,Map<Boolean,List<Integer>>,Map<Boolean,List<Integer>>> {
@Override
public Supplier<Map<Boolean, List<Integer>>> supplier() {
return ()->new HashMap<Boolean, List<Integer>>(){{
put(true,new ArrayList<>());
put(false,new ArrayList<>());
}};
}
@Override
public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
return (Map<Boolean,List<Integer>> map,Integer integer)->{
map.get(isPrime(map.get(true),integer)).add(integer);
};
}
@Override
public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
return (Map<Boolean,List<Integer>> map1,Map<Boolean,List<Integer>> map2)->{
map1.get(true).addAll(map2.get(true));
map1.get(false).addAll(map2.get(false));
return map1;
};
}
@Override
public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
}
public static boolean isPrime(List<Integer> primes, int candidate){
int candidateRoot = (int) Math.sqrt((double) candidate);
return takeWhile(primes, i -> i <= candidateRoot)
.stream()
.noneMatch(p -> candidate % p == 0);
}
public static <A> List<A> takeWhile(List<A> list, Predicate<A> p) {
int i = 0;
for (A item : list) {
if (!p.test(item)) {
return list.subList(0, i);
}
i++;
}
return list;
}
public Map<Boolean, List<Integer>> partitionPrimesWithCustomCollector(int n) {
return IntStream.rangeClosed(2, n).boxed().collect(new PrimeNumbersCollector());
}
}
也可以只在一个方法内实现:
/**
* 也可以直接在collect方法中写,第一个参数相当于supplier方法,
* 第二个参数相当于accumulator方法,
* 第三个参数相当于combiner方法
* @param n
* @return
*/
public Map<Boolean, List<Integer>> partitionPrimesWithCustomCollector
(int n) {
return IntStream.rangeClosed(2, n).boxed()
.collect(
() -> new HashMap<Boolean, List<Integer>>() {{
put(true, new ArrayList<Integer>());
put(false, new ArrayList<Integer>());
}},
(acc, candidate) -> {
acc.get( isPrime(acc.get(true), candidate) )
.add(candidate);
},
(map1, map2) -> {
map1.get(true).addAll(map2.get(true));
map1.get(false).addAll(map2.get(false));
});
}