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

时间:2021-02-19 20:22:36

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 ::或者显然不存在。怎么办?

7 个解决方案

#1


36  

Try this:

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

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

map方法为您提供Optional >。然后,orElseGet方法将其展平为Optional 。只有firstChoice()返回空的optional时,才会计算secondChoice方法。

#2


5  

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.
  • 最坏的情况是第一选择返回false,因此另一种方法调用第二选择。

#3


4  

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]

#4


2  

Maybe something like this :

也许是这样的:

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

From : Chaining Optionals in Java 8

来自:Java 8中的链接选项

#5


0  

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的选项,其中包含或:

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

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

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

#6


0  

Lazy computations and arbitrary number of Optional elements

延迟计算和任意数量的Optional元素

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

#7


-1  

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

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

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:

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

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

#1


36  

Try this:

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

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

map方法为您提供Optional >。然后,orElseGet方法将其展平为Optional 。只有firstChoice()返回空的optional时,才会计算secondChoice方法。

#2


5  

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.
  • 最坏的情况是第一选择返回false,因此另一种方法调用第二选择。

#3


4  

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]

#4


2  

Maybe something like this :

也许是这样的:

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

From : Chaining Optionals in Java 8

来自:Java 8中的链接选项

#5


0  

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的选项,其中包含或:

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

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

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

#6


0  

Lazy computations and arbitrary number of Optional elements

延迟计算和任意数量的Optional元素

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

#7


-1  

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

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

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:

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

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