Java 可选 and orElse

Java Optional and orElse

我是 Java 选项的新手,但我看到这段代码是由另一位开发人员编写的,但我不明白:

String t = null;
Optional.ofNullable("notnull")
    .orElse(
        Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))
    );

为什么这段代码会抛出异常?为什么它甚至会转到 "orElse" 分支?

这是因为一些奇怪的执行顺序吗?所以在评估 orElse 分支之前没有设置第一个可选值?

问题是按执行顺序。 它正在尝试计算 .orElse(...) 的值并在 .orElseThrow 上抛出 MyException。

换句话说,如果 t 不为空,执行流程如下:

1) 计算

的值
Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))

2) 在

中使用 (1) 中的值
Optional.ofNullable("notnull").orElse(...)

orElse 流从未被调用,但方法本身被执行。这意味着方法参数也传递给它。因此,无论传递给第一个 Optional.ofNullable 调用的值如何,都会调用部分 Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))

如果您不希望这种情况发生,您需要像这样传递 Supplier

String t = null;
Optional.ofNullable("notnull")
    .orElseGet(
        () -> Optional.ofNullable(t).orElseThrow(() -> new RuntimeException("MyException"))
    );

供应商仅在 orElseGet 流被调用时被调用。 请注意,您需要 RuntimeException 而不是已检查的异常才能脱离供应商。

你写的是这样的:

String t = null;
String myException = Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"));
Optional.ofNullable("notnull").orElse(myException);

OptionalorElse 部分在您知道您的值是否为 null 或 not.If 您想要 "Lazy" 评估之前评估 orElseGet 方法。

那是因为orElse() will be always evaluated. In other words it will be executed even if you specify a non-empty Optional里面的代码,所以才会抛出Exception

如果您查看 Java Optional – orElse() vs orElseGet() 文章的 orElse() 部分,您可以在他们的示例中看到:

We can easily infer that the parameter of orElse() is evaluated even when having a non-empty Optional.

结果是预期的,因为在 Java 调用带有参数的方法之前,JVM 之前所做的事情是评估参数值。
那就是 .orElse() 调用的参数值:

Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))

由于 t 引用 null,因此预计会抛出异常。

我真的很想知道为什么这段代码是以这种方式编写的。似乎它需要触发一个异常,并在可选中添加一个显式的 NULL 值。

如前所述,当使用 orElse() 而不是 orElseGet() 时,无论 T 的值如何(例如 Optional<T>),都会对方法求值。

为了更好的时尚和理解,我会使用:

String value = "notnull"; // could be null
Optional.ofNullable(value)
    .orElseThrow(MyException::new);

如果值为 NULL,则会触发异常。

注意:您可以使用方法引用来调用异常

关于 Optional 有几点需要注意:

  1. 如果知道被包装的值是否为空,使用Optional.of() or Optional.empty(). If not sure, (for example value is a variable you got from somewhere else) use Optional.ofNullable()

  2. Optional.orElse() and Optional.orElseGet()之间有一个重要的区别。

    1. orElse 取一个已经计算的值,如果提供了一个表达式,它会立即执行和评估。 这发生在有问题的代码中。因此,这个 else 变体应该用于已经可用的值或原语。

    2. orElseGet 采用 Supplier 函数,当评估可选链并请求替代值时,该函数仅 运行 。这应该在替代值的生成或计算成本很高的情况下使用。

    // Fine
    Optional<String> name = Optional.of(someValue).orElse("defaultName");
    
    // But this:
    Optional<String> name = Optional.of(someValue).orElse(db.queryName());
    
    // Is better written as following, as it saves you from an expensive operation
    Optional<String> name = Optional.of(someValue).orElseGet(() -> db.queryName());