【问题标题】:Proper usage of Optional.ifPresent()正确使用 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检查。

有什么想法吗?

【问题讨论】:

    标签: java lambda java-8 optional


    【解决方案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());
    }
    

    这段代码的优点是

    1. 可读
    2. 易于调试(断点)
    3. 不难

    仅仅因为 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
    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2018-11-03
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 2015-06-09
    • 2021-02-02
    相关资源
    最近更新 更多