在函数式语言中,通常在可选类型上使用模式匹配:
let result = match myOptional with
| Some x -> x * 2
| None -> 0
这对程序员非常有帮助,因为编译器检查模式匹配是否完整。
但是,在我看过的Java Optional
示例中,使用的是isPresent
和get
:
Integer result;
if (myOptional.isPresent()) {
result = myOptional.get() * 2;
} else {
result = 0;
}
对我而言,这违背了Optional
的目的。编译器不会检查以确保if
的两个分支都正确实现,并且生成的代码没有使用null
的等效代码。
此设计选择会降低安全性,那么为什么标准库提供get
功能而不仅仅是match
?
答案 0 :(得分:7)
这是通过the Optional::map
method完成的。你的例子可以写成:
Integer result = myOptional.map(i -> i * 2).orElse(0);
关于get
方法,有a discussion弃用它 - 我不确定是否已达成决定。
答案 1 :(得分:4)
上面的F#片段更安全,因为它可以确保始终初始化结果。离开这两种情况中的任何一种都是编译时错误。
它也将在Java中:Java使用definite assignment来确保初始化本地和最终变量。
请注意,这与Optional
无关,具体而言:只要编译器确定在使用此类变量之前未对其进行初始化,就会产生错误。
例如:
int result;
if (someCondition) {
result = 0;
}
System.out.println(result); // result might not have been initialized.
因此,实际上没有任何东西"不安全"关于这个设计(关于本地或最终变量的分配)。
答案 2 :(得分:1)
是的,通常你应该避免打电话给get()
。但是,有时这是唯一令人满意的解决方案,因为lambda表达式的功能相当有限。以下是lambdas无法做到的事情清单:
throws
声明考虑这个例子:
if (opt.isPresent()) {
int value = opt.get();
if (value == 0) {
throw new Exception("Catastrophical error!");
} else {
// ...
}
}
由于Consumer
不支持已检查的异常,因此您无法以简单的方式使用lambdas重写此代码段。
lambdas的其他缺点:
所以,最后的答案是:尝试编写正确且功能正常的代码。由于get()
可能会影响代码的正确性,因此请尽量避免使用它。但是,如果你遇到lambdas的限制,请不要使用get()
。当他们看到可读的代码片段而不是修改外部可变变量或在lambda中抛出已检查异常的丑陋变通方时,您的同事会感谢您。