java 结合可选项的最优雅方式是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32776705/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 20:45:38  来源:igfitidea点击:

What's the most elegant way to combine optionals?

javajava-8optional

提问by Sebastian Oberhoff

Here's what I've got so far:

这是我到目前为止所得到的:

Optional<Foo> firstChoice = firstChoice();
Optional<Foo> secondChoice = secondChoice();
return Optional.ofNullable(firstChoice.orElse(secondChoice.orElse(null)));

This strikes me as both hideous and wasteful. If firstChoice is present I am needlessly computing secondChoice.

这让我觉得既可怕又浪费。如果存在 firstChoice,我将不必要地计算 secondChoice。

There's also a more efficient version:

还有一个更高效的版本:

Optional<Foo> firstChoice = firstChoice();
if(firstChoice.isPresent()) {
 return firstChoice;
} else {
 return secondChoice();
}

Here I can't chain some mapping function to the end without either duplicating the mapper or declaring another local variable. All of this makes the code more complicated than the actual problem being solved.

在这里,我不能在不复制映射器或声明另一个局部变量的情况下将某些映射函数链接到最后。所有这些使得代码比要解决的实际问题更复杂。

I'd much rather be writing this:

我更愿意写这个:

return firstChoice().alternatively(secondChoice());

However Optional::alternatively obviously doesn't exist. Now what?

然而 Optional::alternatively 显然不存在。怎么办?

回答by marstran

Try this:

试试这个:

firstChoice().map(Optional::of)
             .orElseGet(this::secondChoice);

The map method gives you an Optional<Optional<Foo>>. Then, the orElseGetmethod flattens this back to an Optional<Foo>. The secondChoicemethod will only be evaluated if firstChoice()returns the empty optional.

map 方法为您提供了一个Optional<Optional<Foo>>. 然后,该orElseGet方法将其展平回Optional<Foo>. 该secondChoice方法仅在firstChoice()返回空的可选时才会被评估。

回答by Marthym

Maybe something like this :

也许是这样的:

Optional<String> finalChoice = Optional.ofNullable(firstChoice()
    .orElseGet(() -> secondChoice()
    .orElseGet(() -> null)));

From : Chaining Optionals in Java 8

来自:Java 8 中的链式可选项

回答by Suresh Atta

You can simply replace that with,

您可以简单地将其替换为,

Optional<Foo> firstChoice = firstChoice();
return firstChoice.isPresent()? firstChoice : secondChoice();

The above code won't call unless firstChoice.isPresent()is false.

除非firstChoice.isPresent()为 false,否则上面的代码不会调用。

But you have to be prepare to call both functions to get the desired output. There is no other way to escape the checking.

但是您必须准备好调用这两个函数以获得所需的输出。没有其他方法可以逃避检查。

  • Best case is First choice returning true.
  • Worst case will be First choice returning false, hence another method call for second choice.
  • 最好的情况是返回 true 的首选。
  • 最坏的情况是 First choice 返回 false,因此另一个方法调用第二个选项。

回答by Tagir Valeev

Here's the generalization of @marstran solution for any number of optionals:

这是@marstran 解决方案对任意数量选项的概括:

@SafeVarargs
public static <T> Optional<T> selectOptional(Supplier<Optional<T>>... optionals) {
    return Arrays.stream(optionals)
            .reduce((s1, s2) -> () -> s1.get().map(Optional::of).orElseGet(s2))
            .orElse(Optional::empty).get();
}

Test:

测试:

public static Optional<String> first() {
    System.out.println("foo called");
    return Optional.empty();
}

public static Optional<String> second() {
    System.out.println("bar called");
    return Optional.of("bar");
}

public static Optional<String> third() {
    System.out.println("baz called");
    return Optional.of("baz");
}

public static void main(String[] args) {
    System.out.println(selectOptional(() -> first(), () -> second(), () -> third()));
}

Output:

输出:

foo called
bar called
Optional[bar]

回答by Erik

I was frustrated enough by the fact that this wasn't supported in java 8, that I switched back to guava's optionals which have or:

Java 8 不支持这一点,这让我感到非常沮丧,于是我又切换回了 guava 的可选选项,它具有or

public abstract Optional<T> or(Optional<? extends T> secondChoice)

Returns this Optional if it has a value present; secondChoice otherwise.

如果存在值,则返回此 Optional ;secondChoice 否则。

回答by Pepe-Soft

Lazy computations and arbitrary number of Optionalelements

惰性计算和任意数量的Optional元素

Stream.<Supplier<Optional<Foo>>>of(
        this::firstChoice,
        this::secondChoice
).map(
        Supplier::get
).filter(
        Optional::isPresent
).findFirst(
).orElseGet(
    Optional::empty
);

回答by Denis Bazhenov

Here is a way which works for arbitrary number of Optional's based in a stream API:

这是一种适用于Optional基于流 API 的任意数量的's 的方法:

return Arrays.asList(firstChoice, secondChoice).stream()
  .filter(Optional::isPresent)
  .map(Optional::get)
  .findFirst().orElse(null);

It's not the shortest one. But more plain and understandable.

这不是最短的。但更通俗易懂。

Another way is to use firstNonNull()from Guava of commons-lang if you are already using one of those libraries:

firstNonNull()如果您已经在使用其中一个库,另一种方法是从 commons-lang 的 Guava 中使用:

firstNonNull(firstChoice.orElse(null), secondChoice.orElse(null));