java8新特性-引用流-findAny,findFirst

Stream的执行流程参考https://www.cnblogs.com/shigongp/p/17181380.html。
 
findAny和findFirst都是从Stream中查找一个元素。它们的不同在于findAny不注重顺序,findFirst注重顺序。

 

例子:

 List<User> users = new ArrayList<>();
 users.add(new User("张三",30));
 users.add(new User("李四",34));
 users.add(new User("王五",20));


 ptional<User> any = users.stream().findAny();
 System.out.println(any.get());

 Optional<User> first = users.stream().findFirst();
 System.out.println(first.get());

运行结果:

 

源码分析:

 

ReferencePipeline#findAny()

 @Override
public final Optional<P_OUT> findAny() {
    return evaluate(FindOps.makeRef(false));
}

主要看FindOps.makeRef。

FindOps#makeRef

  public static <T> TerminalOp<T, Optional<T>> makeRef(boolean mustFindFirst) {
    return new FindOp<>(mustFindFirst, StreamShape.REFERENCE, Optional.empty(),
                        Optional::isPresent, FindSink.OfRef::new);
}


   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;
    }

从FindOp构造函数看到findAny操作的Sink由sinkSupplier提供,即FindSink.OfRef。

从OfRef定义中看到,OfRef继承FindSink:

  static final class OfRef<T> extends FindSink<T, Optional<T>> {
        @Override
        public Optional<T> get() {
            return hasValue ? Optional.of(value) : null;
        }
    }

现在看看FindSink:

private static abstract class FindSink<T, O> implements TerminalSink<T, O> {
    boolean hasValue;
    T value;

    FindSink() {} // Avoid creation of special accessor

    @Override
    public void accept(T value) {
        if (!hasValue) {
            hasValue = true;
            this.value = value;
        }
    }

    @Override
    public boolean cancellationRequested() {
        return hasValue;
    }

    /** Specialization of {@code FindSink} for reference streams */
    static final class OfRef<T> extends FindSink<T, Optional<T>> {
        @Override
        public Optional<T> get() {
            return hasValue ? Optional.of(value) : null;
        }
    }

    /** Specialization of {@code FindSink} for int streams */
    static final class OfInt extends FindSink<Integer, OptionalInt>
            implements Sink.OfInt {
        @Override
        public void accept(int value) {
            // Boxing is OK here, since few values will actually flow into the sink
            accept((Integer) value);
        }

        @Override
        public OptionalInt get() {
            return hasValue ? OptionalInt.of(value) : null;
        }
    }

    /** Specialization of {@code FindSink} for long streams */
    static final class OfLong extends FindSink<Long, OptionalLong>
            implements Sink.OfLong {
        @Override
        public void accept(long value) {
            // Boxing is OK here, since few values will actually flow into the sink
            accept((Long) value);
        }

        @Override
        public OptionalLong get() {
            return hasValue ? OptionalLong.of(value) : null;
        }
    }

    /** Specialization of {@code FindSink} for double streams */
    static final class OfDouble extends FindSink<Double, OptionalDouble>
            implements Sink.OfDouble {
        @Override
        public void accept(double value) {
            // Boxing is OK here, since few values will actually flow into the sink
            accept((Double) value);
        }

        @Override
        public OptionalDouble get() {
            return hasValue ? OptionalDouble.of(value) : null;
        }
    }
}

主要看accept方法。hasValue默认是false。如果hasValue为false,则将value设置到FindSink的value中,同时将hasValue设置为true。

 
 
 

findAny和findFirst不同在于:

 public final Optional<P_OUT> findAny() {
    return evaluate(FindOps.makeRef(false));
}

 @Override
public final Optional<P_OUT> findFirst() {
    return evaluate(FindOps.makeRef(true));
}

传入的标志不一样。通过FindOps.makeRef构造函数传入的标志位最终设置到FindOp的mustFindFirst字段中。

FindOp#getOpFlags()

    @Override
    public int getOpFlags() {
        return StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
    }

mustFindFirst影响了Stream的操作特征。mustFindFirst为false表示Stream有NOT_ORDERED特征,不注重元素顺序。

posted @ 2023-03-12 22:15  shigp1  阅读(1477)  评论(0编辑  收藏  举报