Java上的get()是可选的危险吗?

时间:2017-01-09 14:39:36

标签: java functional-programming

在函数式语言中,通常在可选类型上使用模式匹配:

let result = match myOptional with 
             | Some x -> x * 2
             | None -> 0

这对程序员非常有帮助,因为编译器检查模式匹配是否完整。

但是,在我看过的Java Optional示例中,使用的是isPresentget

Integer result;
if (myOptional.isPresent()) {
    result = myOptional.get() * 2;
} else {
    result = 0;
}

对我而言,这违背了Optional的目的。编译器不会检查以确保if的两个分支都正确实现,并且生成的代码没有使用null的等效代码。

此设计选择会降低安全性,那么为什么标准库提供get功能而不仅仅是match

3 个答案:

答案 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.

Ideone demo

Ideone demo, using OP's code

因此,实际上没有任何东西"不安全"关于这个设计(关于本地或最终变量的分配)。

答案 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中抛出已检查异常的丑陋变通方时,您的同事会感谢您。