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);
Optional
的 orElse
部分在您知道您的值是否为 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 有几点需要注意:
如果知道被包装的值是否为空,使用Optional.of() or Optional.empty(). If not sure, (for example value is a variable you got from somewhere else) use Optional.ofNullable()
Optional.orElse() and Optional.orElseGet()之间有一个重要的区别。
orElse
取一个已经计算的值,如果提供了一个表达式,它会立即执行和评估。 这发生在有问题的代码中。因此,这个 else 变体应该用于已经可用的值或原语。
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());
我是 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);
Optional
的 orElse
部分在您知道您的值是否为 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 有几点需要注意:
如果知道被包装的值是否为空,使用Optional.of() or Optional.empty(). If not sure, (for example value is a variable you got from somewhere else) use Optional.ofNullable()
Optional.orElse() and Optional.orElseGet()之间有一个重要的区别。
orElse
取一个已经计算的值,如果提供了一个表达式,它会立即执行和评估。 这发生在有问题的代码中。因此,这个 else 变体应该用于已经可用的值或原语。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());