美文网首页程序员
Java Stream find操作(六)

Java Stream find操作(六)

作者: 风骚无俩 | 来源:发表于2018-11-01 11:42 被阅读0次

    Stream Head的构建(一)
    Stream 的中间操作(二)
    Stream的终止操作(三)
    这篇看看流的find操作,中间流的操作以前分析过,这里省略以简化

    List<String> names= Arrays.asList("one", "two", "three", "four");
    Optional<String> optionalAny = names.stream().findAny();
    Optional<String> optionalFirst = names.stream().findFirst();
    

    两个方法只是传入参数不一样

    ReferencePipeline.java
     @Override
        public final Optional<P_OUT> findFirst() {
            必须找到第一个,不论是串行还是并行
            return evaluate(FindOps.makeRef(true));
        }
    
        @Override
        public final Optional<P_OUT> findAny() {
            找到就行,不管在元素在序列的顺序
            return evaluate(FindOps.makeRef(false));
        }
    

    和以往的一样,终止操作由一个工厂提供

    FindOps.java
    public static <T> TerminalOp<T, Optional<T>> makeRef(boolean mustFindFirst) {
            return new FindOp<>(mustFindFirst, StreamShape.REFERENCE, Optional.empty(),
                                Optional::isPresent, FindSink.OfRef::new);
        }
    
     private static final class FindOp<T, O> implements TerminalOp<T, O> {
            private final StreamShape shape;
            final boolean mustFindFirst;
            final O emptyValue;
            final Predicate<O> presentPredicate;
            final Supplier<TerminalSink<T, O>> sinkSupplier;
    
            /**
             *
             * @param mustFindFirst 是否必须找到第一个
             * @param emptyValue 没找到返回的值
             * @param presentPredicate 并行处理使用
             * @param sinkSupplier supplier
             */
            FindOp(boolean mustFindFirst,
                           StreamShape shape,
                           O emptyValue,
                           Predicate<O> presentPredicate,
                           Supplier<TerminalSink<T, O>> sinkSupplier) {
                this.mustFindFirst = mustFindFirst;
                this.shape = shape;
                this.emptyValue = emptyValue;
                this.presentPredicate = presentPredicate;
                this.sinkSupplier = sinkSupplier;
            }
            @Override
            public int getOpFlags() {
                短路操作标记
                return StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
            }
            ...
            @Override
            public <S> O evaluateSequential(PipelineHelper<T> helper,
                                            Spliterator<S> spliterator) {
                和以前分析类似,result就是TerminalSink的get方法返回值
                O result = helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).get();
                return result != null ? result : emptyValue;
            }
    
           ...
        }
    

    重点看一下FindOp构造参数的传递,先看emptyValue的赋值

    Optional.java
    Optional简单看是一个数据包装类,但里面有很多转化操作
    public static<T> Optional<T> empty() {
            @SuppressWarnings("unchecked")
            Optional<T> t = (Optional<T>) EMPTY;
            return t;
        }
    
    防止反复实例化
     private static final Optional<?> EMPTY = new Optional<>();
    
     private Optional() {
            this.value = null;
        }
    
    public void ifPresent(Consumer<? super T> consumer) {
            if (value != null)
                consumer.accept(value);
        }
    

    在Lambda和函数式接口有这样一张图,显示了三种方法应用和其对于的Lambda表达式,下面会用到。

    method_referece.png
    presentPredicate直观的实现是这样的
    Predicate<Optional> isPresent = new Predicate<Optional>() {
                @Override
                public boolean test(Optional o) {
                    return o.isPresent();
                }
            };
     使用Lambda表达式
     Predicate<Optional> isPresent = o -> o.isPresent();
     
    方法引用 对于图中第二种方法引用
    Predicate<Optional> isPresent = Optional::isPresent;
    
    构造函数属静态方法,对应第一种方法引用类型。无构造参数
    Supplier<TerminalSink<T, O>> sinkSupplier=FindSink.OfRef::new
    
    

    调用流程参考前文,不再赘述,看关键操作

    private static abstract class FindSink<T, O> implements TerminalSink<T, O> {
            boolean hasValue;
            T value;
            @Override
            public void accept(T value) {
                简单易懂,只要接到元素就终止
                if (!hasValue) {
                    hasValue = true;
                    this.value = value;
                }
            }
    
            @Override
            public boolean cancellationRequested() {
                return hasValue;
            }
    
            static final class OfRef<T> extends FindSink<T, Optional<T>> {
                @Override
                public Optional<T> get() {
                    简单封装,这里null感觉可以直接返回Optional.empty
                    return hasValue ? Optional.of(value) : null;
                }
            }
     }
    

    Optional提供了优雅处理Null问题,一下示例来自这篇

    class Outer {
        Nested nested;
    }
    class Nested {
        Inner inner;
    }
    class Inner {
        String foo;
    }
    
    Outer outer = new Outer();
    if (outer != null && outer.nested != null && outer.nested.inner != null) {
        System.out.println(outer.nested.inner.foo);
    }
    
    

    如果用Optional处理,此时的Optional像流一样。对Kotlin来说还是啰嗦

    Optional.of(new Outer())
        .flatMap(o -> Optional.ofNullable(o.nested))
        .flatMap(n -> Optional.ofNullable(n.inner))
        .flatMap(i -> Optional.ofNullable(i.foo))
        .ifPresent(System.out::println);
    

    相关文章

      网友评论

        本文标题:Java Stream find操作(六)

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