先介绍一段代码
Person p1 = new Person("hehe", 20);
Person p2 = new Person("wang", 20);
Person p6 = new Person("hou", 25);
Person p5 = new Person("hou", 25);
Person p3 = new Person("mabi", 30);
Person p4 = new Person("li", 30);
List<Person> personList = Arrays.asList(p1, p2, p3, p4, p5, p6);
List<String> per1 = personList.stream()
.map(Person::getName).filter(String::toUpperCase).collect(toList()); --收集成集合
复制代码
这是最常用 最简单的函数式编程,经过包装后甚至类似于执行一个SQL;你只需要传入一些Predicate等 函数,就可以达到预期。 下面我们来研究下 collect(toList()) 究竟发生了什么。
collect方法主要做收集使用,但并不意味着就要收集成集合,请记住这句话。
R collect(Collector super T, A, R> collector); ->这是大多数人使用的 该方法要求传入一个 Collector ,返回一个R ->这是另一个稍微底层的API
一切都要源于 collect(Collector super T, A, R> collector);中的Collector
public interface Collector<T, A, R> {
Supplier<A> supplier();
BiConsumer<A, T> accumulator();
BinaryOperator<A> combiner();
Function<A, R> finisher();
Set<Characteristics> characteristics();
//...略
}
复制代码
Collector是一个接口,其中有几个抽象方法 supplier、accumulator、combiner、finisher、characteristics,当你构造一个它的实现类,传给collec(),就会按照你的要求来进行收集!
Supplier supplier()提供一个函数式接口 T get();Supplier s1 = HashSet::new Supplier s2 = ArrayList::newStringBuilder::new, 创建一个StringBuilder来收集CharSequence 我们完成了容器初步的搭建2.BiConsumer accumulator() 提供一个计算器, void accept(T t, U u);
List::add ->将元素加入ListStringBuilder::append -〉将CharSequence加入StringBuilder 我们完成了流中元素和容器间的关系Function finisher() 提供一个最终的返回结果4.Set 这是一个声明: 1、排序问题UNORDERED,集合中是否按照顺序排呀? 2、并发问题CONCURRENT,可以支持多个线程操作(accumulator)同一个 A容器 3、容器和最终返回结果是否一致IDENTITY_FINISH finisher()中,A==R ?
BinaryOperator combiner() 提供一个融合器,这个是用在并发流中的;R apply(T t, U u) 这个是严格的public class Collector_custom {
public static void main(String[] args) {
Set<Integer> collect = Arrays.asList(1, 2, 3, 3, 4, 5, 6).stream().collect(new MyCollector<Integer>());
System.out.println(collect);
}
public static class MyCollector<T> implements Collector<T, Set<T>, Set<T>> {
@Override
public Supplier<Set<T>> supplier() {
System.out.println("MyCollector.supplier");
return HashSet::new; -->我们提供一个HashSet
}
@Override
public BiConsumer<Set<T>, T> accumulator() {
System.out.println("MyCollector.accumulator");
return Set::add; -->我们处理Set 和流中元素T的关系
}
@Override
public BinaryOperator<Set<T>> combiner() {
System.out.println("MyCollector.combiner");
return (st1, st2) -> {
st1.addAll(st2);
return st1; ->如果是并发流,创建了多个容器,我们处理多个容器间的关系
};
}
@Override
public Function<Set<T>, Set<T>> finisher() {
System.out.println("MyCollector.finisher");
return Function.identity(); -> 处理 容器和最终返回的规约,我们选择都是返回Set<T>
}
@Override
public Set<Characteristics> characteristics() {
System.out.println("MyCollector.characteristics");
return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, UNORDERED));
--> 当我们使用了 IDENTITY_FINISH ,其实就不用再写finisher();不知道你明不明白?
--> UNORDERED 不追求顺序,我们毕竟用的HashSet
}
}
}
复制代码
java8自己也有实现: 和我们实现的有点区别,我们已经对5个参数实现好了, 它是需要用户自己传,这就是函数式编程!
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;
//自己传入 5个参数,
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;
}
}
复制代码
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);
//用了内置的静态类CollectorImpl,传入了ArrayList::new,List::add、(left, right) -> { left.addAll(right); return left;
//CH_ID 就是一个实现好了的Set枚举集合
}
复制代码
1、finisher()执行的时机
public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
A container;
if (isParallel()
&& (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
&& (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
container = collector.supplier().get();
BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
forEach(u -> accumulator.accept(container, u));
}
else {
//假设我们是串行
container = evaluate(ReduceOps.makeRef(collector));
}
//这里看到了IDENTITY_FINISH的作用吗? 如果有就返回 container,没有才去finisher()
return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
? (R) container
: collector.finisher().apply(container);
}
复制代码
2、其他方法的执行时机 ->ReduceOps.makeRef(collector)
makeRef(Collector<? super T, I, ?> collector) {
//执行了!
Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
BiConsumer<I, ? super T> accumulator = collector.accumulator();
BinaryOperator<I> combiner = collector.combiner();
class ReducingSink extends Box<I>
implements AccumulatingSink<T, I, ReducingSink> {
@Override
public void begin(long size) {
state = supplier.get();
}
@Override
public void accept(T t) {
accumulator.accept(state, t);
}
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
@Override
public int getOpFlags() {
//这里对UNORDERED 进行判断
return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
? StreamOpFlag.NOT_ORDERED
: 0;
}
};
}
复制代码
熟悉了Collector后,看Collectors的所有方法,都会非常简单。