可选 orElse 可选 Java
Optional orElse Optional in Java
我一直在使用新的 Optional type in Java 8,我遇到了一个看似常见但功能上不受支持的操作:"orElseOptional"
考虑以下模式:
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);
}
这种模式有多种形式,但它归结为想要一个 "orElse" 可选的,它接受一个函数来产生一个新的可选,只有当当前的可选不存在时才调用。
它的实现看起来像这样:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
return value != null ? this : other.get();
}
我很好奇是否存在这种方法不存在的原因,如果我只是以一种意想不到的方式使用 Optional,以及人们想出什么其他方法来处理这种情况。
我应该说,我认为涉及自定义实用程序的解决方案 classes/methods 并不优雅,因为使用我的代码的人不一定知道它们的存在。
另外,如果有人知道,这样的方法会不会包含在JDK9中,我在哪里可以提出这样的方法?对我来说,这似乎是对 API 的一个非常明显的遗漏。
也许这就是您想要的:Get value from one Optional or another
否则,您可能想看看Optional.orElseGet
。下面是我认为你想要的例子:
result = Optional.ofNullable(serviceA().orElseGet(
() -> serviceB().orElseGet(
() -> serviceC().orElse(null))));
它不是很漂亮,但它会起作用:
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)
是与 Optional
一起使用的相当方便的模式。意思是"If this Optional
contains value v
, give me func(v)
, otherwise give me sup.get()
"。
在这种情况下,我们调用 serviceA(args)
并得到一个 Optional<Result>
。如果那个Optional
包含值v
,我们想要得到Optional.of(v)
,但是如果它是空的,我们想要得到serviceB(args)
。用更多替代品冲洗重复。
此模式的其他用途是
.map(Stream::of).orElseGet(Stream::empty)
.map(Collections::singleton).orElseGet(Collections::emptySet)
鉴于当前 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();
重要的方面不是您必须编写一次的(恒定的)操作链,而是添加另一个服务(或一般修改服务列表)是多么容易。在这里,添加或删除单个 ()->serviceX(args)
就足够了。
由于流的惰性评估,如果前面的服务返回非空值,则不会调用任何服务 Optional
。
从 Java9 开始,您可以将代码简化为
Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
()->serviceA(args),
()->serviceB(args),
()->serviceC(args),
()->serviceD(args))
.flatMap(s -> s.get().stream())
.findFirst();
虽然 已经包含一个更简单的 JDK 9 方法。
JDK 16 提供替代方案
Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
()->serviceA(args),
()->serviceB(args),
()->serviceC(args),
()->serviceD(args))
.<Result>mapMulti((s,c) -> s.get().ifPresent(c))
.findFirst();
尽管这种方法对于接受 Consumer
而不是返回 Supplier
的服务方法可能更方便。
这看起来很适合模式匹配和更传统的 Option 接口,带有 Some 和 None 实现(例如 Javaslang, FunctionalJava) or a lazy Maybe implementation in cyclops-react 中的实现)。我是这个库的作者。
和cyclops-react you can also use structural pattern matching on JDK types. For Optional you can match on the present and absent cases via the visitor pattern。它看起来像这样 -
import static com.aol.cyclops.Matchables.optional;
optional(serviceA(args)).visit(some -> some ,
() -> optional(serviceB(args)).visit(some -> some,
() -> serviceC(args)));
这是 JDK 9 的一部分,形式为 or
,需要一个 Supplier<Optional<T>>
。您的示例将是:
return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args));
详情见the Javadoc or this post我写的
假设您仍在使用 JDK8,则有多种选择。
选项#1:制作您自己的辅助方法
例如:
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);
}
}
这样你就可以做到:
return Optionals.or(
()-> serviceA(args),
()-> serviceB(args),
()-> serviceC(args),
()-> serviceD(args)
);
选项#2:使用库
例如google guava 的 Optional 支持适当的 or()
操作(就像 JDK9),例如:
return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args))
.or(() -> serviceD(args));
(其中每个服务 returns com.google.common.base.Optional
,而不是 java.util.Optional
)。
我一直在使用新的 Optional type in Java 8,我遇到了一个看似常见但功能上不受支持的操作:"orElseOptional"
考虑以下模式:
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);
}
这种模式有多种形式,但它归结为想要一个 "orElse" 可选的,它接受一个函数来产生一个新的可选,只有当当前的可选不存在时才调用。
它的实现看起来像这样:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
return value != null ? this : other.get();
}
我很好奇是否存在这种方法不存在的原因,如果我只是以一种意想不到的方式使用 Optional,以及人们想出什么其他方法来处理这种情况。
我应该说,我认为涉及自定义实用程序的解决方案 classes/methods 并不优雅,因为使用我的代码的人不一定知道它们的存在。
另外,如果有人知道,这样的方法会不会包含在JDK9中,我在哪里可以提出这样的方法?对我来说,这似乎是对 API 的一个非常明显的遗漏。
也许这就是您想要的:Get value from one Optional or another
否则,您可能想看看Optional.orElseGet
。下面是我认为你想要的例子:
result = Optional.ofNullable(serviceA().orElseGet(
() -> serviceB().orElseGet(
() -> serviceC().orElse(null))));
它不是很漂亮,但它会起作用:
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)
是与 Optional
一起使用的相当方便的模式。意思是"If this Optional
contains value v
, give me func(v)
, otherwise give me sup.get()
"。
在这种情况下,我们调用 serviceA(args)
并得到一个 Optional<Result>
。如果那个Optional
包含值v
,我们想要得到Optional.of(v)
,但是如果它是空的,我们想要得到serviceB(args)
。用更多替代品冲洗重复。
此模式的其他用途是
.map(Stream::of).orElseGet(Stream::empty)
.map(Collections::singleton).orElseGet(Collections::emptySet)
鉴于当前 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();
重要的方面不是您必须编写一次的(恒定的)操作链,而是添加另一个服务(或一般修改服务列表)是多么容易。在这里,添加或删除单个 ()->serviceX(args)
就足够了。
由于流的惰性评估,如果前面的服务返回非空值,则不会调用任何服务 Optional
。
从 Java9 开始,您可以将代码简化为
Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
()->serviceA(args),
()->serviceB(args),
()->serviceC(args),
()->serviceD(args))
.flatMap(s -> s.get().stream())
.findFirst();
虽然
JDK 16 提供替代方案
Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
()->serviceA(args),
()->serviceB(args),
()->serviceC(args),
()->serviceD(args))
.<Result>mapMulti((s,c) -> s.get().ifPresent(c))
.findFirst();
尽管这种方法对于接受 Consumer
而不是返回 Supplier
的服务方法可能更方便。
这看起来很适合模式匹配和更传统的 Option 接口,带有 Some 和 None 实现(例如 Javaslang, FunctionalJava) or a lazy Maybe implementation in cyclops-react 中的实现)。我是这个库的作者。
和cyclops-react you can also use structural pattern matching on JDK types. For Optional you can match on the present and absent cases via the visitor pattern。它看起来像这样 -
import static com.aol.cyclops.Matchables.optional;
optional(serviceA(args)).visit(some -> some ,
() -> optional(serviceB(args)).visit(some -> some,
() -> serviceC(args)));
这是 JDK 9 的一部分,形式为 or
,需要一个 Supplier<Optional<T>>
。您的示例将是:
return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args));
详情见the Javadoc or this post我写的
假设您仍在使用 JDK8,则有多种选择。
选项#1:制作您自己的辅助方法
例如:
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);
}
}
这样你就可以做到:
return Optionals.or(
()-> serviceA(args),
()-> serviceB(args),
()-> serviceC(args),
()-> serviceD(args)
);
选项#2:使用库
例如google guava 的 Optional 支持适当的 or()
操作(就像 JDK9),例如:
return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args))
.or(() -> serviceD(args));
(其中每个服务 returns com.google.common.base.Optional
,而不是 java.util.Optional
)。