美文网首页
Java Stream match操作(五)

Java Stream match操作(五)

作者: 风骚无俩 | 来源:发表于2018-10-31 17:31 被阅读0次

    Stream Head的构建(一)
    Stream 的中间操作(二)
    Stream的终止操作(三)
    本篇讲述match操作,省略中间流操作,有以下三种方式,方法名已经说明的其功能

    List<String> names= Arrays.asList("one", "two", "three", "four");
    boolean anyMatch = names.stream().anyMatch(s -> s.length()>2);
    boolean allMatch = names.stream().allMatch(s -> s.length()<10);
    boolean noneMatch = names.stream().noneMatch(s -> s.length()!=5);
    

    从源码看,调用的方法相同,只是参数不一样,下文会分析其意义

    ReferencePipeline.java
     @Override
        public final boolean anyMatch(Predicate<? super P_OUT> predicate) {
            return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ANY));
        }
    
        @Override
        public final boolean allMatch(Predicate<? super P_OUT> predicate) {
            return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ALL));
        }
    
        @Override
        public final boolean noneMatch(Predicate<? super P_OUT> predicate) {
            return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.NONE));
        }
    
    

    终止操作构建的套路差不多

    MatchOps.java
    public static <T> TerminalOp<T, Boolean> makeRef(Predicate<? super T> predicate,
                MatchKind matchKind) {
            Objects.requireNonNull(predicate);
            Objects.requireNonNull(matchKind);
            //先忽略
            class MatchSink extends BooleanTerminalSink<T> {
                MatchSink() {
                    super(matchKind);
                }
                @Override
                public void accept(T t) {
                    if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
                        stop = true;
                        value = matchKind.shortCircuitResult;
                    }
                }
            }
            return new MatchOp<>(StreamShape.REFERENCE, matchKind, MatchSink::new);
        }
    
    

    这里使用构造函数的方法引用实例化Supplier<BooleanTerminalSink<T>>接口,sinkSupplier.get()的调用才会真正new对象。不熟悉可以参考这篇

    private static final class MatchOp<T> implements TerminalOp<T, Boolean> {
            private final StreamShape inputShape;
            final MatchKind matchKind;
            final Supplier<BooleanTerminalSink<T>> sinkSupplier;
                   MatchOp(StreamShape shape,
                    MatchKind matchKind,
                    Supplier<BooleanTerminalSink<T>> sinkSupplier) {
                this.inputShape = shape;
                this.matchKind = matchKind;
                this.sinkSupplier = sinkSupplier;
            }
            @Override
            public int getOpFlags() {
                注意操作标记是短路的,表示流元素可能发了一部分就被叫停了。后面会用到
                return StreamOpFlag.IS_SHORT_CIRCUIT | StreamOpFlag.NOT_ORDERED;
            }
            ...
            @Override
            public <S> Boolean evaluateSequential(PipelineHelper<T> helper,
                                                  Spliterator<S> spliterator) {
                return helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).getAndClearState();
            }
           ...
        }
    

    在wrapAndCopyInto之前,需要讲一下MatchKind,有三个枚举类型ANY、ALL、NONE,意义如下

    enum MatchKind {
             找一个符合条件的,短路返回true 
            ANY(true, true),
    
            找到一个不合法条件的,短路返回false 
            ALL(false, false),
    
            找到一个符合条件的,短路返回false 
            NONE(true, false);
            对判断结果的期望,any期望true,all期望false,none期望true,一旦期望成真即短路
            private final boolean stopOnPredicateMatches;
            发生短路返回的值
            private final boolean shortCircuitResult;
    
            private MatchKind(boolean stopOnPredicateMatches,boolean shortCircuitResult) {
                this.stopOnPredicateMatches = stopOnPredicateMatches;
                this.shortCircuitResult = shortCircuitResult;
            }
        }
    

    MatchSink使用MatchKind作为参数调用父类BooleanTerminalSink初始化返回值value,对短路结果取反

    private static abstract class BooleanTerminalSink<T> implements Sink<T> {
            boolean stop;
            boolean value;
    
            BooleanTerminalSink(MatchKind matchKind) {
                value = !matchKind.shortCircuitResult;
            }
    
            public boolean getAndClearState() {
                return value;
            }
    
            @Override
            public boolean cancellationRequested() {
                return stop;
            }
        }
    

    和以前一样来到这里,不同的是这次标记是SHORT_CIRCUIT

    AbstractPipeline
     @Override
        final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
            Objects.requireNonNull(wrappedSink);
            if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
                ...
            }
            else {
                //有短路操作
                copyIntoWithCancel(wrappedSink, spliterator);
            }
        }
    
    
     final <P_IN> void copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
            @SuppressWarnings({"rawtypes","unchecked"})
            AbstractPipeline p = AbstractPipeline.this;
            //回到源头
            while (p.depth > 0) {
                p = p.previousStage;
            }
            wrappedSink.begin(spliterator.getExactSizeIfKnown());
            p.forEachWithCancel(spliterator, wrappedSink);
            wrappedSink.end();
        }
    

    这里和以前略有不同,我们不需要遍历整个数据源,只要下游达到目的就能提前收工。每发射一次都有问一下是否继续

    ReferencePipeline
    @Override
        final void forEachWithCancel(Spliterator<P_OUT> spliterator, Sink<P_OUT> sink) {
            do { } while (!sink.cancellationRequested() && spliterator.tryAdvance(sink));
        }
    

    再看看MatchSink对元素的处理,这是整个功能的核心。

    @Override
    public void accept(T t) {
        开始stop=false,判断式是否符合期望,如前面所述
        ANY-->期望predicate.test(t) 表达式返回true
        ALL-->期望predicate.test(t) 表达式返回false
        NONE-->期望predicate.test(t)表达式返回true
        判断短小精悍  
        if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
            stop = true;
            value = matchKind.shortCircuitResult;
        }
    }
    
    

    一旦达到期望,stop=true,即请求取消;重新给value赋值,这是我们达到期望要返回的值。如果遍历到结束,说明大失所望,value值就是之前的取反值

    private static abstract class BooleanTerminalSink<T> implements Sink<T> {
            boolean stop;
            boolean value;
    
            BooleanTerminalSink(MatchKind matchKind) {
                value = !matchKind.shortCircuitResult;
            }
    
            public boolean getAndClearState() {
                return value;
            }
    
            @Override
            public boolean cancellationRequested() {
                return stop;
            }
        }
    

    相关文章

      网友评论

          本文标题:Java Stream match操作(五)

          本文链接:https://www.haomeiwen.com/subject/croatqtx.html