Java 为什么我们可以在可选的.of()上调用.orElse()?

Java 为什么我们可以在可选的.of()上调用.orElse()?,java,java-8,optional,Java,Java 8,Optional,我很好奇为什么可以这样做(至少在Java8上): 可选。of(null)基本上是一个保证的空指针。在它上面调用.orElse()会给笨拙的开发人员带来意想不到的漏洞。我一直在四处寻找,看是否有理由这样做。也许这应该解决某些情况?您可以这样做,原因与您可以编写((String)null).length()相同。Java编译器有一个静态检查器来检查某些事情,比如类型安全,但不检查或拒绝可证明抛出NullPointerException的代码。如果是,则代码抛出新的NullPointerExcepti

我很好奇为什么可以这样做(至少在Java8上):


可选。of(null)
基本上是一个保证的空指针。在它上面调用
.orElse()
会给笨拙的开发人员带来意想不到的漏洞。我一直在四处寻找,看是否有理由这样做。也许这应该解决某些情况?

您可以这样做,原因与您可以编写
((String)null).length()
相同。Java编译器有一个静态检查器来检查某些事情,比如类型安全,但不检查或拒绝可证明抛出
NullPointerException
的代码。如果是,则代码
抛出新的NullPointerException()也将不被允许

通常情况下,抛出异常的代码不是错误。虽然静态检查器可以检测到这种情况并发出警告,但如果这是一个错误,那就太糟糕了。有些IDE会针对可能的错误生成自己的警告,但您必须决定哪些是值得检查的,哪些是不值得检查的


检测这种可能的错误需要一个静态检查器,该检查器的设计应了解
可选方法的行为。的作者已经决定对不安全强制转换之类的事情发出警告,但对任何依赖于所使用方法的语义的事情都不发出警告。这一决定的一个优点是,它意味着JLS可以与文档分开维护。

有些语言支持直接在编译器中进行空检查(或者甚至更好的语言根本没有这种“东西”)——这会被烧到编译器中

javac
不是这样的编译器,坦率地说,我也不希望它变成这样。有些语言有语法,比如
-当我阅读此代码时,它要么对我尖叫,要么问我一些问题(这是我的意见)

现在,回想一下
Optional
是为返回类型设计的,因此在方法体中使用
Optional
方法链。如果您真的想检查某个内容是否为空,那么就使用它;如果不确定某个内容是否为空,可以使用
可选::of nullable

我知道并阅读了
Optional::of
Optional::of nullable
的参数,我仍然不喜欢它,我希望它只是后者。但是,大家不必总是同意:我们确实有
可选::isEmpty
可选::isPresent
。这是个好决定吗?我不知道

与任何其他方法调用一样,您可以将
null
传递给任何对象引用,
Optional
也不例外。他们是否可以为
javac
添加语义以仅支持
Optional::of
和空检查?可能请问有多少人会要求对和此功能提供这样的支持

显然,上面的代码总是会导致异常。但是关于:

Optional.of(someMethod()).orElse();

你可能会想:当然,同样的事情

事实上,这是错误的。如果子类重写
someMethod()
以返回除
null
以外的值,该怎么办?!因此,您无法在编译时决定该方法在运行时是否总是返回null

长话短说:编译器可以应用各种技术(如数据流分析)来确定代码是否会导致运行时异常,这有很多明显的情况,也有一些不太明显的情况。但也有许多其他地方不可能做到这一点

这里的要点是:由定义语言的人来决定他们希望编译器关心什么


java人选择了简单的编译器。一个编译速度快、实现起来不太复杂的程序。为什么?因为编译器只是避免了过于复杂的检查。

javac
不支持在传递null时进行检查,这与任何其他方法调用没有太大区别。@Eugene我想说的是,问题更多的是
javac
Optional
的语义没有感觉,所以它不知道这一行在实践中意味着什么。
orElse
与任何方法一样,它基于变量的类型,而不是实例本身。在这里,您有一个
可选的
,仅此而已。将发生的异常是一个运行时异常,因此它可能发生,也可能不发生,这不在编译器的手上,而是在您的手上。当实际错误是将在运行时失败的表达式
Optional.of(null)
时,您为什么要关注调用
.orElse()
的能力?为什么您认为允许
Optional.of(null)
而不允许
.orElse()
会更好?@kaya3因为
javac
不是一个IDE。关于
Optional::isEmpty
Optional::isPresent
,我认为两者都是一个很好的设计选择
isEmpty
是容器类型的标准方法,
isPresent
作为
Stream.filter
的方法引用传递很有用,因此您不必每次都将
.filter(o->!o.isEmpty())
作为lambda函数编写。@kaya3有时我希望
Stream
具有某种“
排除(谓词)”
“它可以简单地委托给
过滤器(predicate.negate())
。虽然你的论点显然不仅仅适用于
Stream
Optional.of(null).orElse();
Optional.of(someMethod()).orElse();
Object someMethod() { return null; }