Java8 Stream实现原理,源码浅析(下)

2023年 10月 16日 32.9k 0

前言

上文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

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论