正确使用 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&lt;User&gt;.ifPresent()Consumer&lt;? super User&gt; 作为参数。您正在向它传递一个类型为 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&lt;User&gt; 的函数,通常不需要将它存储在局部变量中。只需链接方法调用: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 的功能风格?

如何正确的使用SharedPreferences

如何正确使用 Composer 安装 Laravel 扩展包

如何正确使用 Composer 安装 Laravel 扩展包

如何正确使用 Composer 安装 Laravel 扩展包