tl;博士
您显示的代码“我知道这不能编译”实际上应该编译。该代码是您的解决方案。
使用类似的代码,看这个方法:
public Optional < DayOfWeek > getFavoriteDayOfWeek ( )
{
return Optional.ofNullable( DayOfWeek.WEDNESDAY ); // Silly implementation for demonstration.
}
…这样称呼:
this.getFavoriteDayOfWeek().ifPresent(
( DayOfWeek dow ) -> { … dow.get() … }
);
…运行live successfully at IdeOne.com。
请记住,Optional 是它自己的对象,包装了一些其他对象作为其有效负载。所以要小心你的类型声明:Optional<DayOfWeek> someVar 与 DayOfWeek someVar。
返回Optional
如果 null 在您的域中是可接受的值,则返回 Optional。返回从Optional 中解包的null 违背了Optional 的目的。
purpose of an Optional 是向调用方法发出信号,表明 null 确实是一种有效的可能性。 Java 的类型系统被用来提醒调用程序员编写null 的可能性。一个Optional 对象就像一个大的safety-orange 交通标志,上面写着:“当心:前面可能是NULL”。
仅返回从 Optional 中解包的 null 不会增加任何价值,并且会产生脆弱的代码。
问题中显示的代码不必要地跳过了额外的箍,只是引入了额外的间接级别而没有任何好处。如果null 的有效负载是有效结果,则调用方法确实应该收到Optional。
所以这个:
//in class Bar
public Foo getFooIfItIsPresent(String param) {
Optional<Foo> result = loadOptionalFoo(param);
if (result.isPresent()) {
return result.get();
} else {
return null;
}
// main driver code
Foo foo = Bar.getFooIfItIsPresent(param);
if (foo != null) {
// Currently just print, but might want to do stuff like pass foo to another object, etc.
System.out.println(foo.getSomething() + foo.getSomethingElse());
}
……应该是:
//in class Bar
// ➥ Delete this method `getFooIfItIsPresent`. Adds no value.
// public Foo getFooIfItIsPresent(String param)
……和……
// main driver code
Optional<Foo> result = someBar.loadOptionalFoo( param );
if ( result.isPresent() ) {
// Currently just print, but might want to do stuff like pass foo to another object, etc.
Foo foo = result.get() ; // Calling `get` is safe because we checked for null in the `if … isPresent` line above.
System.out.println( foo.getSomething() + foo.getSomethingElse() ) ;
}
请注意我们如何调用Optional::get,仅在调用Optional::ifPresent 来检查null 之后。
如果您想要解决Optional 为空且不存在Foo 对象的if else 条件,Optional 类提供了多种方法。参见orElse、orElseGet、orElseThrow等方法。
您的有问题的代码确实应该编译
你说这段代码不能编译:
Bar.loadOptionalFoo(param).ifPresent((foo) -> {
// Print, or whatever I wanna do!
System.out.println(foo.getSomething() + foo.getSomethingElse());
});
实际上,该代码应该可以编译。这样做是完全合理的,这是我在上面展示的解决方案的另一种变体。
这是一个类似的例子。我使用Java内置的DayOfWeek枚举类创建了getFavoriteDayOfWeek方法,它返回一个Optional< DayOfWeek >。如果注册了最喜欢的一天,则该方法返回一个Optional,其中包含一个DayOfWeek 对象。如果尚未确定收藏夹,则该方法返回一个空的Optional。这是该方法的虚拟版本。
public Optional < DayOfWeek > getFavoriteDayOfWeek ( )
{
return Optional.ofNullable( DayOfWeek.WEDNESDAY );
}
使用与您的代码类似的代码调用该方法:
this.getFavoriteDayOfWeek().ifPresent(
( DayOfWeek dayOfWeek ) -> {
// Print, or whatever I wanna do!
System.out.println( dayOfWeek.getDisplayName( TextStyle.FULL , Locale.CANADA_FRENCH ) );
}
);
运行时:
默契
INFO - 已完成运行演示。
您可以将WEDNESDAY 对象更改为null 以进行实验。
public Optional < DayOfWeek > getFavoriteDayOfWeek ( )
{
return Optional.ofNullable( null );
}
运行时,我们看到 System.out.println( dayOfWeek.getDisplayName(… 代码从未被调用,因为我们的 Optional<DayOfWeek> 实际上包含 DayOfWeek 对象 (ifPresent) 的条件测试未得到满足。我们只能看到第二个System.out.println 的输出,即“Done running”。
INFO - 已完成运行演示。
看到这个code run live at IdeOne.com。
制作Optional
您的问题的主体似乎在询问从Optional 中提取值。我在上面展示了。
您的问题的标题似乎是关于将值包装在 Optional 中。
- 如果您知道要返回
null,请返回 Optional.empty()。
- 如果返回的内容可能为 null,也可能不为 null,请返回
Optional.ofNullable( x )。
- 如果在这种情况下返回的东西绝对不为空,则返回
Optional.of( x )。如果值为 null,则该方法将抛出 NullPointerException。当 null 的存在意味着您的应用出现严重问题时,请使用此方法。
顺便说一下,在看到您使用if (foo != null) { 之后的提示:
如果您确实需要测试null,我建议您不要使用x != null 或x == null,而是分别使用Objects 类方法Objects.nonNull( Object obj ) 和Objects.isNull( Object obj )。
更好的是,在无法容忍 null 存在的情况下,这意味着您的代码中出现重大意外故障,请致电 Objects.requireNonNull( T obj )。如果接收到 null,则此方法抛出 NullPointerException。更好的是,此方法返回传递的对象。这使得它非常适合将传递的参数分配给其他变量。
public void doSomething( final Fruit fruit , final DayOfWeek dayOfWeek )
{
this.fruit = Objects.requireNonNull( fruit ) ;
this.dayOfWeek = Objects.requireNonNull( dayOfWeek ) ;
}
最后提示:Java 14 带来了更多有用的NullPointerException 对象,更好地定位故障位置。见JEP 358: Helpful NullPointerExceptions。