【问题标题】:When I need to use Optional.orElseGet() over Optional.orElse()当我需要使用 Optional.orElseGet() 而不是 Optional.orElse()
【发布时间】:2017-10-30 20:53:18
【问题描述】:

我需要对此进行清楚的解释,尽管我阅读了 link 的差异但没有明确的解释。那么有人可以用代码简短地向我解释一下吗?

【问题讨论】:

  • 接受的答案有什么不清楚的地方?
  • 我没有得到清晰的答案
  • 如果在“orElse”情况下生成要返回的值需要一些计算,我的喜好可能是orElseGet(),以便仅在需要时执行计算。如果计算有副作用,您应该根据是始终需要这些副作用还是仅在需要对象时进行选择。
  • orElse() 在大多数情况下是自然的选择。在我们的代码库中,我们使用了 31 次 orElse() 和 0 次 orElseGet()
  • @OleV.V.我刚才做了同样的事情 :) orElseGet 的一种用法 - 返回的对象来自数据库调用。

标签: java java-8 optional


【解决方案1】:

我想我开始理解你的问题了。 Optional 的执行顺序可能与我们在过程编程中习惯的不同(Java 流和其他使用 lambda 的代码也是如此)。

我将使用Eugene’s answer中的两个例子:

    o1.orElse(new MyObject()); // 1055e4af 

这是普通的旧 Java:它是对 orElse() 的调用,以 new MyObject() 作为参数。所以首先评估参数并创建一个新的MyObject。然后将其传递给orElse()orElse() 查看Optional 中是否存在值;如果是,则返回该值(丢弃新创建的对象);如果不是,它返回参数中给它的对象。这是一个更简单的例子。

    o1.orElseGet(() -> {
        System.out.println("Should I see this");
        return new MyObject();
    });

再一次,我们有一个带有一个参数的方法调用,并且再次首先评估该参数。 lambda 仅作为供应商创建和传递。 { } 中的代码尚未执行(您在 Eugene 的输出中也没有看到 Should I see this)。再次orElseGet 查看Optional 中是否存在值。如果有,则返回该值并忽略我们传递的供应商。如果没有,则调用供应商,执行{ } 中的代码以获取要从orElseGet() 返回的值。

在第一种情况下,有人可能会说 MyObject 被创建并被浪费了。在第二个中,Supplier 被创建并浪费了。在这两种情况下,您得到的都是简洁且空指针安全的代码。所以很多时候,你选择哪一个并不重要。如果创建MyObject 成本高或有不必要的副作用,您当然会想要第二个版本,其中仅在请求时创建对象,并且永远不会浪费。 Eugene 在评论中提到了返回对象来自数据库调用的情况。数据库调用通常非常耗时,以至于您不想无缘无故地调用。

【讨论】:

  • 喜欢!你的措辞是完美的国际海事组织。一加
  • 如果可选(o1)返回空,那么“orElse”也将返回空???就像下面的示例代码 String x =null;可选 o1 = Optional.ofNullable(x); o1.orElse("po");
  • 你试过了吗?答案是否定的,在这种情况下orElse() 将返回"po"
  • 是的,我试过了,orElse 将输出返回为“Optional.empty”
  • 很奇怪。听起来您已经打印了Optional(调用它的toString()),而不是来自orElse() 的返回字符串。
【解决方案2】:

举个例子吧:

static class MyObject {
    public MyObject() {
        System.out.println("Creating one..." + this);
    }
}

还有一些用法:

  Optional<MyObject> o1 = Optional.of(new MyObject()); // 7382f612

    o1.orElse(new MyObject()); // 1055e4af 
    o1.orElseGet(() -> {
        System.out.println("Should I see this");
        return new MyObject();
    });

还有一些输出:

 Creating one... MyObject@7382f612
 Creating one... MyObject@1055e4af

如果Optional有值orElse 仍被调用但未使用。对矛盾的orElseGet 没有调用。

考虑创建对象代价高昂的情况;你会用哪一个?

我认为如果您查看代码,实际上更容易理解:

public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}

【讨论】:

  • 只有一个混乱,,,一次 orElse 和 orElseGet 将执行?不是按照上面的代码
  • 我是唯一一个仍被调用但未使用看起来像糟糕的 API 设计的人吗?调用某些东西但不使用它的原因是什么?是不是类似于try-catch表达式中的finally
  • @MikeB。那怎么相似? finally总是被调用。还有多少次你写了new HashMap&lt;&gt;() 例如只添加两个条目,例如 - 保留了更多空间,但你没有使用它。很可能orElse(new ArrayList&lt;&gt;()) 会比调用Supplier 产生一个更便宜。
  • @Eugene,据我了解,orElse() 总是被调用,无论orElse() 所属的对象是null 还是null
  • @MikeB。现在我明白你的意思了,是的,orElse 总是被调用;不确定这是否是一个糟糕的 API 决定。有时创建一个对象而不使用它比遵循某些可能创建它的方法更便宜 - 我真的认为这里就是这种情况。
【解决方案3】:

正如here 的回答,当所需资源的获取成本很高时,您可能需要考虑第二种方法。

// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource()); 

// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource()) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-18
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    相关资源
    最近更新 更多