Optional 被添加到 Java 中的原因是:
return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.getOrThrow(() -> new InternalError(...));
比这更干净:
Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;
我的观点是,Optional 是为了支持函数式编程而编写的,它同时被添加到 Java 中。 (这个例子来自blog by Brian Goetz。更好的例子可能是使用orElse() 方法,因为这段代码无论如何都会抛出异常,但你明白了。)
但是现在,人们使用 Optional 的原因非常不同。他们正在使用它来解决语言设计中的缺陷。缺陷在于:无法指定 API 的哪些参数和返回值允许为空。它可能会在 javadocs 中提及,但大多数开发人员甚至不会为他们的代码编写 javadocs,而且很少有人会在编写时检查 javadocs。所以这导致很多代码在使用它们之前总是检查空值,即使它们通常不可能为空,因为它们已经在调用堆栈上重复验证了九到十倍。
我认为解决这个缺陷真的很迫切,因为很多看到新 Optional 类的人都认为它的目的是增加 API 的清晰度。这就是为什么人们会问诸如“getter 应该返回 Optionals 吗?”之类的问题。不,他们可能不应该,除非您希望 getter 用于函数式编程,这不太可能。事实上,如果你看Java API中Optional的使用情况,主要是在Stream类中,它们是函数式编程的核心。 (我没有仔细检查过,但 Stream 类可能是唯一使用它们的地方。)
如果您确实打算在一些函数式代码中使用 getter,那么拥有一个标准 getter 和另一个返回 Optional 的 getter 可能是个好主意。
哦,如果你需要你的类是可序列化的,你绝对不应该使用 Optional。
选项对于 API 缺陷来说是一个非常糟糕的解决方案,因为 a)它们非常冗长,并且 b)它们从一开始就没有打算解决这个问题。
API 缺陷的更好解决方案是Nullness Checker。这是一个注释处理器,可让您通过使用 @Nullable 注释来指定允许哪些参数和返回值为空。这样,编译器可以扫描代码并确定是否将实际上可以为 null 的值传递给不允许 null 的值。默认情况下,它假定任何内容都不允许为空,除非它被注释。这样,您就不必担心空值。将空值传递给参数将导致编译器错误。测试不能为 null 的对象会产生编译器警告。这样做的效果是将 NullPointerException 从运行时错误更改为编译时错误。
这改变了一切。
至于你的吸气剂,不要使用可选的。并尝试设计您的类,使所有成员都不可能为空。也许尝试将 Nullness Checker 添加到您的项目中,并在需要时声明您的 getter 和 setter 参数@Nullable。我只在新项目中这样做过。它可能会在现有项目中产生很多警告,其中包含大量多余的 null 测试,因此可能很难进行改造。但它也会捕获很多错误。我喜欢它。正因为如此,我的代码更干净、更可靠。
(还有一种新语言可以解决这个问题。Kotlin 编译为 Java 字节码,允许您在声明对象时指定它是否可以为空。这是一种更简洁的方法。)
原帖附录(第 2 版)
经过深思熟虑,我不情愿地得出结论,在一个条件下返回 Optional 是可以接受的:检索到的值实际上可能为 null。我见过很多代码,人们经常从不可能返回 null 的 getter 中返回 Optional。我认为这是一种非常糟糕的编码实践,只会增加代码的复杂性,从而更容易出现错误。但是当返回值实际上可能为 null 时,请继续将其包装在 Optional 中。
请记住,为函数式编程而设计且需要函数引用的方法将(并且应该)以两种形式编写,其中一种使用 Optional。例如,Optional.map() 和 Optional.flatMap() 都采用函数引用。第一个引用一个普通的 getter,第二个引用一个返回 Optional 的引用。因此,在值不能为 null 的情况下,返回 Optional 并没有帮到任何人的忙。
说了这么多,我仍然认为Nullness Checker 使用的方法是处理空值的最佳方法,因为它们将 NullPointerExceptions 从运行时错误转变为编译时错误。