\`Optional.orElse()\` 和 \`Optional.orElseGet()\` 的区别

新手上路,请多包涵

我试图了解 Optional<T>.orElse()Optional<T>.orElseGet() 方法之间的区别。

orElse() 方法的描述是 “如果存在则返回值,否则返回其他”。

orElseGet() 方法的描述是 “如果存在则返回值,否则调用其他方法并返回该调用的结果。”

orElseGet() 方法采用 Supplier 功能接口,基本上不采用任何参数并返回 T

在哪种情况下您需要使用 orElseGet() ?如果你有一个方法 T myDefault() 你为什么不做 optional.orElse(myDefault()) 而不是 optional.orElseGet(() -> myDefault())

似乎 orElseGet() 将 lambda 表达式的执行推迟到以后的某个时间或其他时间,那么它有什么意义呢? (I would have thought that it would be more useful if it returned a safer Optional<T> whose get() never throws a NoSuchElementException and isPresent() always返回 true… 但显然不是,它只是返回 T 就像 orElse() )。

我还缺少其他区别吗?

原文由 jbx 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

以这两种情况为例:

 Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );

如果 opt 不包含值,则两者确实等价。但是,如果 opt 包含 一个值,将创建多少 Foo 对象?

Ps:当然在这个例子中,差异可能无法衡量,但是如果您必须从远程 Web 服务或数据库中获取默认值,它突然变得非常重要。

原文由 biziclop 发布,翻译遵循 CC BY-SA 3.0 许可协议

简短回答:

  • orElse() 将始终调用给定函数,无论您是否需要,无论 Optional.isPresent() 值如何
  • orElseGet() 只会在 Optional.isPresent() == false 时调用给定函数

在实际代码中,当所需资源的 获取成本很高 时,您可能需要考虑第二种方法。

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

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

有关更多详细信息,请考虑以下使用此功能的示例:

 public Optional<String> findMyPhone(int phoneId)

区别如下:

                            X : buyNewExpensivePhone() called

+——————————————————————————————————————————————————————————————————+——————————————+
|           Optional.isPresent()                                   | true | false |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone())          |   X  |   X   |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) |      |   X   |
+——————————————————————————————————————————————————————————————————+——————————————+

optional.isPresent() == false 时,两种方式没有区别。但是,当 optional.isPresent() == true , orElse() 时,无论您是否需要,总是调用后续函数。

最后使用的测试用例如下:

结果:

 ------------- Scenario 1 - orElse() --------------------
  1.1. Optional.isPresent() == true (Redundant call)
    Going to a very far store to buy a new expensive phone
    Used phone: MyCheapPhone

  1.2. Optional.isPresent() == false
    Going to a very far store to buy a new expensive phone
    Used phone: NewExpensivePhone

------------- Scenario 2 - orElseGet() --------------------
  2.1. Optional.isPresent() == true
    Used phone: MyCheapPhone

  2.2. Optional.isPresent() == false
    Going to a very far store to buy a new expensive phone
    Used phone: NewExpensivePhone

代码:

 public class TestOptional {
    public Optional<String> findMyPhone(int phoneId) {
        return phoneId == 10
                ? Optional.of("MyCheapPhone")
                : Optional.empty();
    }

    public String buyNewExpensivePhone() {
        System.out.println("\tGoing to a very far store to buy a new expensive phone");
        return "NewExpensivePhone";
    }

    public static void main(String[] args) {
        TestOptional test = new TestOptional();
        String phone;
        System.out.println("------------- Scenario 1 - orElse() --------------------");
        System.out.println("  1.1. Optional.isPresent() == true (Redundant call)");
        phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");

        System.out.println("  1.2. Optional.isPresent() == false");
        phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");

        System.out.println("------------- Scenario 2 - orElseGet() --------------------");
        System.out.println("  2.1. Optional.isPresent() == true");
        // Can be written as test::buyNewExpensivePhone
        phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");

        System.out.println("  2.2. Optional.isPresent() == false");
        phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");
    }
}

原文由 Hoa Nguyen 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题