findFirst on a Stream<optional<t>&gt;

时间:2015-07-29 00:37:54

标签: java java-stream optional

Say you've got a stream of @IBOutlet var text: UITextField! { didSet { text.delegate = self } } , that you want to fire a Optional<T> on (if present).

What's the most elegant way of handling this?

I can manage by filtering by Consumer<T> and mapping by Optional::isPresent, but that seems "hacky" and not in the spirit of Optional::isGet:

Optional

3 个答案:

答案 0 :(得分:4)

我同意这很麻烦,但它可能是最简单的解决方案而不会变得更加苛刻。

我在类似情况下做的一件事是创建一种方法将Optional变成Stream

private Stream<T> optionalStream(Optional<T> optional) {
    if (optional.isPresent())
        return Stream.of(optional.get());
    else
        return Stream.empty());
}

然后您可以使用flatMap

Stream.of(a, b, c, d)
    .flatMap(this::optionalStream).findFirst()...

当我第一次看到Optional时,我想知道为什么他们没有包含stream方法来执行此操作。更新:Java 9将包含Optional的这种方法。

但说实话,我不确定这比filter然后map解决方案简单得多。

答案 1 :(得分:0)

我不确定下面的方法是否比你的更好......

首先,您可以尝试使用reduce()

Stream.of(a, b, c, d).reduce(Optional.empty(), (o1, o2) -> o1.isPresent() ? o1 : o2)
    .ifPresent(s -> System.out.println("This seems cumbersome as well: " + s));

你仍然在查询Optional,虽然这会在减少流时发生。

更优雅的方法(尽管不是那么冗长)是使用专门的Consumer,只有当非空时才会接受Optional的值。为此,您需要按如下方式定义OptionalConsumer

@FunctionalInterface
interface OptionalConsumer<T>
    extends Consumer<Optional<T>> {

    @Override
    default void accept(Optional<T> o) {
        if (o.isPresent()) {
            this.acceptIfPresent(o.get());
        }
    }

    void acceptIfPresent(T o);

    static <U> OptionalConsumer<U> of(Consumer<U> c) {
        return c::accept;
    }
}

你可以这样使用它:

Stream.of(a, b, c, d).forEach(OptionalConsumer.of(s -> System.out.println("Better? " + s)));

注意:

  1. 当您需要在许多不同的流中执行相同的逻辑时,这种方法可能更好。
  2. 我不认为它在并行流上运行良好。
  3. 由于OptionalConsumer实际上是Consumer,我不知道如何将其与findFirst()一起使用。

答案 2 :(得分:0)

我认为flatMap在这里真的很方便

 Stream.of(a, b, c, d)
   .flatMap(opt -> opt.map(Stream::of).orElse(Stream.empty()))
   .findFirst()
   .ifPresent(s -> System.out.println("This was cumbersome: " + s));

不理想,但至少要简洁。