流式传输直到找到值 - 可选

Stream till value found - optional

我想在找到第一个值时终止流的执行。但是,当我在下面的 运行 代码中显示即使值来自 first 方法,也会调用两个方法。

public static void main(String[] args) {

        Optional<String> s = Stream.of(first(), second())
                .filter(Optional::isPresent)
                .findFirst()
                .flatMap(Function.identity());

        System.out.println(s.get());
    }

    private static Optional<String> first() {
        System.out.println("first");
        return Optional.of("someValue");
    }

    private static Optional<String> second() {
        System.out.println("second");
        return Optional.empty();
    }

我检查了文档:

  1. 存在

Return {@code true} if there is a value present, otherwise {@code false}.

  1. findFirst()

Returns an {@link Optional} describing the first element of this stream, or an empty {@code Optional} if the stream is empty. If the stream has no encounter order, then any element may be returned.

所以第一个条件它满足了,第二个条件似乎也满足了 returns:

first
second
someValue

如果第一个值存在,如何退出执行,而不执行第二个方法?

How to quit execution if first value present, and not execute second method?

Stream#findFirst是短路端子操作。但是,当您调用 Stream.of(first(), second()) 时,将调用这些方法。这可以用以下代码片段证明:

Optional<String> s = Stream.of(first(), second())
                           .peek($ -> System.out.println("Hello World!"))
                           .filter(Optional::isPresent)
                           .findFirst()
                           .flatMap(Function.identity());

System.out.println(s.get());

输出:

first
second
Hello World!
someValue

为了防止 first()second() 在调用 Stream#of 时执行,一种解决方案是将它们包装在 Supplier<Optional<String>>:

Stream<Supplier<Optional<String>>> stream = Stream.of(Test::first, Test::second);

Optional<String> s = stream.map(Supplier::get)
                           .filter(Optional::isPresent)
                           .findFirst()
                           .flatMap(Function.identity());

System.out.println(s.get());

输出:

first
someValue

问题不在于findFirst没有短路,而是Stream.of(first(), second())导致first()second立即(未延迟)执行。它基本上被评估为任何普通表达式。

换句话说,即使你的主要方法只是

final public static void main(String[] args) throws Exception {
    Stream.of(first(), second());
}

它仍然会立即执行first()second()