正确使用 Optional.ifPresent()
Posted
技术标签:
【中文标题】正确使用 Optional.ifPresent()【英文标题】:Proper usage of Optional.ifPresent() 【发布时间】:2014-08-05 08:50:31 【问题描述】:我正在尝试理解 Java 8 中 Optional
API 的 ifPresent()
方法。
我的逻辑很简单:
Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));
但这会导致编译错误:
ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)
当然我可以这样做:
if(user.isPresent())
doSomethingWithUser(user.get());
但这就像一张乱七八糟的null
支票。
如果我把代码改成这样:
user.ifPresent(new Consumer<User>()
@Override public void accept(User user)
doSomethingWithUser(user.get());
);
代码越来越脏,这让我想到回到旧的null
检查。
有什么想法吗?
【问题讨论】:
【参考方案1】:Optional<User>.ifPresent()
将Consumer<? super User>
作为参数。您正在向它传递一个类型为 void 的表达式。所以这不编译。
Consumer 旨在实现为 lambda 表达式:
Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));
或者更简单,使用方法引用:
Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);
这和
基本一样Optional<User> user = ...
user.ifPresent(new Consumer<User>()
@Override
public void accept(User theUser)
doSomethingWithUser(theUser);
);
这个想法是doSomethingWithUser()
方法调用只有在用户在场时才会执行。您的代码直接执行方法调用,并尝试将其 void 结果传递给ifPresent()
。
【讨论】:
那段代码越来越乱了。空检查会更干净。你不觉得吗?特别是 doSomethingWithUser 不是静态方法 哪个代码?您应该使用第二个,它调用实例(即非静态)方法 doSomethingWithUser()。我不明白它是如何混乱的。最后一个代码用于向您解释 lambda 前世界中的 lambda 等价物。不要使用它。 是的,但您可能习惯于匿名类,因此通过查看匿名类等价物来了解 lambda 的作用。这就是重点。 你没有什么要修改的。保持原样,使用第二个示例:user.ifPresent(this::doSomethingWithUser);
@rayman 如果您有一个返回Optional<User>
的函数,通常不需要将它存储在局部变量中。只需链接方法调用:funcThatMightReturnUser().ifPresent(this::doSomethingWithUser);
【参考方案2】:
除了@JBNizet 的回答,我对ifPresent
的一般用例是结合.isPresent()
和.get()
:
老办法:
Optional opt = getIntOptional();
if(opt.isPresent())
Integer value = opt.get();
// do something with value
新方法:
Optional opt = getIntOptional();
opt.ifPresent(value ->
// do something with value
)
对我来说,这更直观。
【讨论】:
但是如果出现在里面的东西应该是返回无效的,因为你从里面返回的任何东西都会丢失 @valik 是的,就是这样。你不应该期望从那里返回一个值;它更像是“这样做”。【参考方案3】:既然可以简化代码,为什么还要编写复杂的代码?
确实,如果您绝对要使用Optional
类,最简单的代码就是您已经编写的...
if (user.isPresent())
doSomethingWithUser(user.get());
这段代码的优点是
-
可读
易于调试(断点)
不难
仅仅因为 Oracle 在 Java 8 中添加了Optional
类,并不意味着在所有情况下都必须使用该类。
【讨论】:
使用 ifPresent 的主要好处是它消除了您手动调用 get() 的需要。手动调用 get() 容易出错,因为很容易忘记先检查 isPresent,但如果使用 ifPresent 则不可能忘记 好的,每次你使用'user'对象时你应该调用.ifPresent()。代码将很快变得不可读,因为您将阅读 .ifPresent() 太多时间!【参考方案4】:你可以像这样使用方法引用:
user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);
方法ifPresent()
将Consumer
对象作为参数和(来自JavaDoc):“如果存在值,则使用该值调用指定的使用者。”值是你的变量user
。
或者如果doSomethingWithUser
这个方法在User
类中而不是static
,你可以像这样使用方法引用:
user.ifPresent(this::doSomethingWithUser);
【讨论】:
但是 doSomethingWithUser 不是静态方法也不是类。 @rayman 好的,如果不是静态的,你可以这样做:user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
@AleksandrPodkutin 您不应该仅仅为了运行一个方法而创建该类的新实例,从 OP 看来,该方法与被调用的方法在同一个类中,因此他应该使用user.ifPresent(this::doSomethingWithUser);
@Marv 我没有看到任何关于它属于同一类的确认形式 OP。但如果你有这样的感觉,我同意他必须使用user.ifPresent(this::doSomethingWithUser);
。我会将其添加到我的答案中。【参考方案5】:
使用平面地图。如果存在值,则 flatMap 返回仅包含该值的顺序 Stream,否则返回空 Stream。所以没有必要使用 ifPresent()
。示例:
list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());
【讨论】:
可选::stream需要java9以上是关于正确使用 Optional.ifPresent()的主要内容,如果未能解决你的问题,请参考以下文章
用 Optional#ifPresent 替换空检查的好处 [重复]
Java 8 的 Optional.ifPresent 和 if-not-Present 的功能风格?
如何正确使用 Composer 安装 Laravel 扩展包