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

时间:2015-09-25 07:11:52

标签: java java-8 optional

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

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

这令我感到羞耻和浪费。如果firstChoice存在,我将不必要地计算secondChoice。

还有一个更有效的版本:

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

在这里,我无法将一些映射函数链接到最终,而无需复制映射器或声明另一个局部变量。所有这些使得代码比实际解决的问题更复杂。

我更愿意写这个:

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

然而,可选::显然不存在。现在怎么样?

7 个答案:

答案 0 :(得分:40)

试试这个:

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

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

答案 1 :(得分:5)

您只需将其替换为

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

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

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

  • 最好的情况是返回真实的第一选择。
  • 最坏的情况将是返回false的第一选择,因此另一种方法 要求第二选择。

答案 2 :(得分:4)

也许是这样的:

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

来自:Chaining Optionals in Java 8

答案 3 :(得分:4)

以下是@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();
}

测试:

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

输出:

foo called
bar called
Optional[bar]

答案 4 :(得分:1)

我对java 8中不支持这个事实感到很沮丧,我转而回到番石榴的选项or

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

如果存在值,则返回此Optional;第二个选择。

答案 5 :(得分:0)

延迟计算和任意数量的Stream.<Supplier<Optional<Foo>>>of( this::firstChoice, this::secondChoice ).map( Supplier::get ).filter( Optional::isPresent ).findFirst( ).orElseGet( Optional::empty ); 元素

{{1}}

答案 6 :(得分:-1)

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

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

它不是最短的。但更简单易懂。

另一种方法是使用来自Guava of commons-lang的firstNonNull(),如果你已经使用了其中一个库:

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