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特征,不注重元素顺序。