前言
上文Java8 Stream实现原理,源码浅析(上)我们介绍了流的创建和中间操作,下面讲一讲Stream的终止操作
三、Stream的终止
终止操作的分类与共性
终止操作又分为「短路操作」和「非短路操作」。
之后又根据不同作用分类。
下面列出一些常用API,读者可以尝试观察它们的共同点和不同点。
短路操作:可以提前终止的操作
如果是短路操作,那么不一定需要完整的遍历整个Stream的元素,在某些条件下,可以提前得到结果,提前结束遍历过程。短路操作有MatchOp和FindOp两个TerminalOp实现,分别表示匹配和查找。
cancellationRequested():如果返回true,表示sink不再处理Stream中后续的元素,用于短路操作。
匹配操作:MatchOp
anyMatch
有一个匹配就立刻返回true
public final boolean anyMatch(Predicate collector) {
// 返回一个 TerminalOp
// supplier 是 ArrayList::new
Supplier supplier = Objects.requireNonNull(collector).supplier();
// accumulator 是 List::add
BiConsumer accumulator = collector.accumulator();
// combiner 是 (left, right) -> { left.addAll(right); return left; }
BinaryOperator combiner = collector.combiner();
// ---------------------
class ReducingSink extends Box
implements AccumulatingSink {
// 就是new一个ArrayList
@Override
public void begin(long size) {
state = supplier.get();
}
// 向ArrayList add一个元素
@Override
public void accept(T t) {
accumulator.accept(state, t);
}
// 向ArrayList add 另一个ArrayList的所有元素
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
// ---------------------
// 以上可以概括为取出CollectorImpl的几个重要的表达式
return new ReduceOp(StreamShape.REFERENCE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
// 省略 getOpFlags
};
}
至此,得到一个ReduceOp实例,并重写了makeSink方法。makeSink用作wrapAndCopyInto方法的入参。
在evaluate时,ReduceOp也会被当成和普通的StatexxxOp一样,被调用begin,end,accept方法,他的sink在整个sinke链条的最后。因此实现了将结果转化为一个ArrayList。
joining():字符串拼接
String result = Stream.of("java", "scala", "go", "python")
.collect(Collectors.joining(","));
System.out.println(result);
// 输出 : java,scala,go,python
// 支持无参直接拼接,也支持分隔符
通过分析toList我们已经知道,Collector只是封装几个函数,因此不同方法只是几个lambda表达式方法和别人的不同,因此后文只关注这些方法。
joining()就是:
public static Collector joining() {
return new CollectorImpl(
StringBuilder::new, // 1
StringBuilder::append, // 2
(r1, r2) -> { r1.append(r2); return r1; },// 3
StringBuilder::toString, // 4
CH_NOID);
}
多写了一个方法:将StringBuilder转化为String,多指定了finisher方法,这在ArrayList没有。
toSet():返回HashSet
public static
Collector toSet() {
return new CollectorImpl(
(Supplier) HashSet::new,
Set::add,
(left, right) -> { left.addAll(right); return left; },
CH_UNORDERED_ID);
}
toMap():返回HashMap
public static
Collector toMap(Function