可选orElse在Java中是可选的
我一直在使用新的,我遇到了一个似乎在功能上不受支持的常见操作:“orElseOptional” 考虑以下模式:可选orElse在Java中是可选的,java,lambda,java-8,optional,java-9,Java,Lambda,Java 8,Optional,Java 9,我一直在使用新的,我遇到了一个似乎在功能上不受支持的常见操作:“orElseOptional” 考虑以下模式: Optional<Result> resultFromServiceA = serviceA(args); if (resultFromServiceA.isPresent) return result; else { Optional<Result> resultFromServiceB = serviceB(args); if (result
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);
}
可选结果fromservicea=serviceA(args);
if(resultFromServiceA.isPresent)返回结果;
否则{
可选结果fromserviceb=serviceB(args);
if(resultFromServiceB.isPresent)返回resultFromServiceB;
else返回服务c(args);
}
这种模式有多种形式,但归根结底,它需要一个可选的“orElse”,该可选的函数生成一个新的可选函数,只有在当前可选函数不存在时才调用
它的实现如下所示:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
return value != null ? this : other.get();
}
public-Optional-orElse(供应商也许这就是您想要的:
否则,您可能需要看一看。以下是我认为您所追求的一个示例:
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)
是一种非常方便的模式,可与可选一起使用。它的意思是“如果此可选包含值v
,请给我func(v)
,否则请给我sup.get()
”
在这种情况下,我们调用serviceA(args)
并得到一个Optional
。如果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();
尽管已经包含了一种更简单的JDK9方法
JDK16提供了另一种选择
可选o=Stream.of(
()->服务A(args),
()->服务B(args),
()->服务C(args),
()->已服务(args))
.mapMulti((s,c)->s.get().ifPresent(c))
.findFirst();
虽然这种方法可能更方便,因为服务方法接受消费者
而不是返回供应商
,但它看起来非常适合模式匹配,并且是一种更传统的选项接口,有一些实现,而没有实现(例如,)或者是中的一个懒惰的实现。我是这个库的作者
通过,您还可以在JDK类型上使用structural。对于可选的,您可以通过匹配当前和不存在的情况。它看起来像这样-
import static com.aol.cyclops.Matchables.optional;
optional(serviceA(args)).visit(some -> some ,
() -> optional(serviceB(args)).visit(some -> some,
() -> serviceC(args)));
这是JDK 9的一部分,形式为或,它采用供应商。您的示例如下:
return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args));
有关详细信息,请参阅或我写的。假设您仍然使用JDK8,有几个选项
选项1:制作自己的助手方法
例如:
选项2:使用库
例如,google guava的可选支持适当的或()
操作(就像JDK9),例如:
(其中每个服务返回com.google.common.base.Optional
,而不是java.util.Optional
).。澄清一下:这已经在Java 9中出现了-如果不是在Java 8的未来更新中的话。是的!谢谢,在我的搜索中没有发现。@Obicere这个问题不适用于这里,因为它是关于空可选的行为,而不是关于替代结果。可选已经有orElseGet()
对于OP所需要的,只是它不能生成很好的级联语法。关于Java的优秀教程可选:只是在项目中使用了它,谢天谢地,我们不做代码审查。它比一系列“OrelGet”要干净得多,但它也很难阅读。这当然是正确的…但老实说,我花了一秒钟来解析它,我没有信心它是正确的。请注意,我意识到这个例子是正确的,但我可以想象一个小的变化,使它不会被懒散地评估或有一些其他错误,这将是无法区分的看一眼。对我来说,这属于一种实用功能。我想知道用.map(可选::get)
切换.findFirst()
是否会更容易“读取”,例如.filter(可选::isPresent).findFirst().map(可选::get)
可以像这样“读取”“在流中找到Optional::isPresent为true的第一个元素,然后通过应用Optional::get将其展平”?有趣的是,我在几个月前发布了一个非常类似的问题。这是我第一次遇到这个问题。嗯,当我使用这个策略时,eclipse说:“方法orElseGet。”(Supplier@chrismarx()->{}
不会返回一个可选的
。你想做什么?我只是想按照下面的例子来做。链接映射调用不起作用。我的服务返回字符串,当然没有.map()选项可用,这是即将推出的或(供应商)的最佳可读替代方案Java的
9@Sheepy你弄错了。.map()
在一个空的Optional
上将产生一个空的Optional
。这是天才们通常做的事情。将可选项评估为空值,并用of nullable
将其包装是我见过的最酷的事情。很好。这个添加一定有一年了,我没有注意到。关于你博客中的问题,更改返回类型将破坏二进制兼容性,因为字节码调用指令引用完整签名,包括返回类型,因此没有机会更改ifPresent
的返回类型。但是无论如何,我认为名称ifPresent
不是一个好名称。对于所有其他不带“else”的方法在名称中(如map
,filter
,flatMap
),意味着如果不存在值,它们什么也不做,那么为什么ifPresent
…那么添加一个可选的perform(Consumer c)
方法来允许链接perfo
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)
);
return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args))
.or(() -> serviceD(args));