java中StreamAPI的Collector原理分析
前言
StreamAPI是java8提供的一种方便,高效操作容器的工具。
简单使用
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Client {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "world");
//字符串转大写
list = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(list);
}
}
Stream对象调用collect()方法,根据不同的Collector返回不同的结果。
/**
* 收集器接口
*/
public interface Collector<T, A, R> {
/**
* 创建一个可变的结果容器
*/
Supplier<A> supplier();
/**
* 将一个元素添加到结果容器中
*/
BiConsumer<A, T> accumulator();
/**
* 合并两个容器
*/
BinaryOperator<A> combiner();
/**
* 进行结果的转换,如果设置了IDENTITY_FINISH标识,该方法不被调用
*/
Function<A, R> finisher();
/**
* 返回该收集器的标识不可变集合
*/
Set<Characteristics> characteristics();
/**
* 标识的定义
*/
enum Characteristics {
/**
* 表示支持并行操作,结果容器要支持多线程
*/
CONCURRENT,
/**
* 表示结果无序
*/
UNORDERED,
/**
* 表示finisher方法是否可以省略
*/
IDENTITY_FINISH
}
}
定义一个自己的Collector
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class MyListCollector<T> implements Collector<T, List<T>, List<T>> {
@Override
public Supplier<List<T>> supplier() {
System.out.println("supplier() invoked");
return () -> {
System.out.println("new a ArrayList");
return new ArrayList<>();
};
}
@Override
public BiConsumer<List<T>, T> accumulator() {
System.out.println("accumulator() invoked");
return (list, item) -> {
System.out.println("list add a item");
list.add(item);
};
}
@Override
public BinaryOperator<List<T>> combiner() {
System.out.println("combiner() invoked");
return (left, right) -> {
System.out.println("left list addAll right");
left.addAll(right);
return left;
};
}
@Override
public Function<List<T>, List<T>> finisher() {
System.out.println("finisher() invoked");
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
}
}
import java.util.Arrays;
import java.util.List;
public class Client {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "world");
//字符串转大写
list = list.stream().map(String::toUpperCase).collect(new MyListCollector<>());
System.out.println(list);
}
}
输出打印结果为
supplier() invoked
accumulator() invoked
combiner() invoked
new a ArrayList
list add a item
list add a item
[HELLO, WORLD]
finisher()方法没有被执行,在包含IDENTITY_FINISH标识时,会进行强制类型转换,没有时才会调用。
combiner()方法在并行流且没有CONCURRENT标识时才会执行,这是因为包含CONCURRENT标识时,并行流只会操作同一个结果容器,不包含时,会创建多个结果容器进行合并。
源码分析
/**
* Simple implementation class for {@code Collector}.
*
* @param <T> the type of elements to be collected
* @param <R> the type of the result
*/
static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A,R> finisher,
Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}
java中的收集器默认实现,一个收集器包括:供应器,累加器,合并器,完成器,标识列表。
/**
* Returns a {@code Collector} that accumulates the input elements into a
* new {@code List}. There are no guarantees on the type, mutability,
* serializability, or thread-safety of the {@code List} returned; if more
* control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
*
* @param <T> the type of the input elements
* @return a {@code Collector} which collects all the input elements into a
* {@code List}, in encounter order
*/
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
我们常用的toList()收集器,返回一个ArrayList,标识列表包含IDENTITY_FINISH,表示中间类型和结果类型相同,可以强制类型转换。