Java 中的可选 orElse 可选

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28818506/
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-08-11 06:52:30  来源:igfitidea点击:

Optional orElse Optional in Java

javalambdajava-8optionaljava-9

提问by Yona Appletree

I've been working with the new Optional type in Java 8, and I've come across what seems like a common operation that isn't supported functionally: an "orElseOptional"

我一直在使用Java 8 中的新Optional 类型,但我遇到了一个看似功能上不受支持的常见操作:“orElseOptional”

Consider the following pattern:

考虑以下模式:

Optional<Result> resultFromServiceA = serviceA(args);
if (resultFromServiceA.isPresent) return result;
else {
    Optional<Result> resultFromServiceB = serviceB(args);
    if (resultFromServiceB.isPresent) return resultFromServiceB;
    else return serviceC(args);
}

There are many forms of this pattern, but it boils down to wanting an "orElse" on an optional that takes a function producing a new optional, called only if the current one does not exist.

这种模式有很多种形式,但归结为需要一个可选项上的“orElse”,它接受一个函数来生成一个新的可选项,只有在当前选项不存在时才调用。

It's implementation would look like this:

它的实现如下所示:

public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
    return value != null ? this : other.get();
}

I'm curious if there's a reason such a method doesn't exist, if I'm just using Optional in an unintended way, and what other ways people have come up with to deal with this case.

我很好奇这样的方法不存在是否有原因,如果我只是以一种非预期的方式使用 Optional,以及人们想出的其他方法来处理这种情况。

I should say that I think that solutions involving custom utility classes/methods aren't elegant because people working with my code won't necessarily know they exist.

我应该说我认为涉及自定义实用程序类/方法的解决方案并不优雅,因为使用我的代码的人不一定知道它们存在。

Also, if anyone knows, will such a method be included in JDK 9, and where might I propose such a method? This seems like a pretty glaring omission to the API to me.

另外,如果有人知道,这种方法是否会包含在 JDK 9 中,我可以在哪里提出这种方法?对我来说,这似乎是 API 的一个非常明显的遗漏。

采纳答案by Nicolai

This is part of JDK 9 in the form of or, which takes a Supplier<Optional<T>>. Your example would then be:

这是 JDK 9 形式的一部分or,它采用Supplier<Optional<T>>. 您的示例将是:

return serviceA(args)
    .or(() -> serviceB(args))
    .or(() -> serviceC(args));

For details see the Javadocor this postI wrote.

有关详细信息,请参阅Javadoc或我写的这篇文章

回答by aioobe

Perhaps this is what you're after: Get value from one Optional or another

也许这就是您所追求的:从一个 Optional 或另一个中获取价值

Otherwise, you may want to have a look at Optional.orElseGet. Here's an example of what I thinkthat you're after:

否则,您可能需要查看Optional.orElseGet. 这是我认为您所追求的示例:

result = Optional.ofNullable(serviceA().orElseGet(
                                 () -> serviceB().orElseGet(
                                     () -> serviceC().orElse(null))));

回答by Misha

It's not pretty, but this will work:

这不是很漂亮,但这会起作用:

return serviceA(args)
  .map(Optional::of).orElseGet(() -> serviceB(args))
  .map(Optional::of).orElseGet(() -> serviceC(args))
  .map(Optional::of).orElseGet(() -> serviceD(args));

.map(func).orElseGet(sup)is a fairly handy pattern for use with Optional. It means "If this Optionalcontains value v, give me func(v), otherwise give me sup.get()".

.map(func).orElseGet(sup)是一个相当方便的模式,用于Optional. 它的意思是“如果这Optional包含价值v,给我func(v),否则给我sup.get()”。

In this case, we call serviceA(args)and get an Optional<Result>. If that Optionalcontains value v, we want to get Optional.of(v), but if it is empty, we want to get serviceB(args). Rinse-repeat with more alternatives.

在这种情况下,我们调用serviceA(args)并得到一个Optional<Result>. 如果它Optional包含 value v,我们想要 get Optional.of(v),但如果它是空的,我们想要 get serviceB(args)。用更多的选择重复冲洗。

Other uses of this pattern are

这种模式的其他用途是

  • .map(Stream::of).orElseGet(Stream::empty)
  • .map(Collections::singleton).orElseGet(Collections::emptySet)
  • .map(Stream::of).orElseGet(Stream::empty)
  • .map(Collections::singleton).orElseGet(Collections::emptySet)

回答by Holger

The cleanest “try services” approach given the current API would be:

给定当前 API 的最干净的“尝试服务”方法是:

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();

The important aspect is not the (constant) chain of operations you have to write once but how easy it is to add another service (or modify the list of services is general). Here, adding or removing a single ()->serviceX(args)is enough.

重要的方面不是您必须编写一次的(恒定)操作链,而是添加另一个服务(或修改服务列表是通用的)是多么容易。在这里,添加或删除单个()->serviceX(args)就足够了。

Due to the lazy evaluation of streams, no service will be invoked if a preceding service returned a non-empty Optional.

由于对流的惰性求值,如果前一个服务返回非空,则不会调用任何服务Optional

回答by John McClean

This is looks like a good fit for pattern matching and a more traditional Option interface with Some and None implementations (such as those in Javaslang, FunctionalJava) or a lazy Maybeimplementation in cyclops-react.I'm the author of this library.

这看起来很适合模式匹配和更传统的带有 Some 和 None 实现的 Option 接口(例如JavaslangFunctionalJava 中的那些)或cyclops -react 中的懒惰Maybe实现。我是这个库的作者。

With cyclops-reactyou can also use structural pattern matchingon JDK types. For Optional you can match on the present and absent cases via the visitor pattern. it would look something like this -

使用cyclops-react,您还可以在 JDK 类型上使用结构模式匹配。对于 Optional,您可以通过访问者模式匹配存在和缺席的情况。它看起来像这样 -

  import static com.aol.cyclops.Matchables.optional;

  optional(serviceA(args)).visit(some -> some , 
                                 () -> optional(serviceB(args)).visit(some -> some,
                                                                      () -> serviceC(args)));

回答by Sheepy

Assuming you're still on JDK8, there are several options.

假设您仍在使用 JDK8,则有多种选择。

Option#1: make your own helper method

选项#1:创建自己的辅助方法

E.g.:

例如:

public class Optionals {
    static <T> Optional<T> or(Supplier<Optional<T>>... optionals) {
        return Arrays.stream(optionals)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst()
                .orElseGet(Optional::empty);
    }
}

So that you could do:

这样你就可以:

return Optionals.or(
   ()-> serviceA(args),
   ()-> serviceB(args),
   ()-> serviceC(args),
   ()-> serviceD(args)
);

Option#2: use a library

选项#2:使用图书馆

E.g. google guava's Optional supports a proper or()operation (just like JDK9), e.g.:

例如 google guava 的 Optional 支持正确的or()操作(就像 JDK9),例如:

return serviceA(args)
  .or(() -> serviceB(args))
  .or(() -> serviceC(args))
  .or(() -> serviceD(args));

(Where each of the services returns com.google.common.base.Optional, rather than java.util.Optional).

(其中每个服务返回com.google.common.base.Optional,而不是java.util.Optional)。