降低空指针的负面影响的最重要的办法,就是不要产生空指针。没有空指针的代码,代码更简洁,风险也更小。
在很多场景下,我们都可以使用空值来替代空指针,比如,空的字符串、空的集合。
不过,不是在所有的情况下我们都能够避免空指针的。如果空指针不能避免,降低空指针的负面影响的另外一个办法,就是在使用空指针的时候,执行强制性的检查。所谓强制性的检查,对于编程语言来说,指的是我们通常能够依赖的是编译器的能力,以及新的接口设计思路。
设计 Optional 的目的,是希望开发者能够先调用它的 Optional.isPresent 方法,然后再调用 Optional.get 方法获得目标对象。 按照设计者的预期,这个 Optional 类的使用应该像下面的代码这样。
private static boolean hasMiddleName(
FullName fullName, String middleName) {
if (fullName.middleName().isPresent()) {
return fullName.middleName().get().equals(middleName);
}
return middleName == null;
}
Optional 带来了不必要的复杂性,然而它并没有简化开发者的工作,也没有解决掉空指针的问题。
我们希望返回值的检查是强制性的。如果不检查,就没有办法得到返回值指代的真实对象。实现的思路,就是使用封闭类和模式匹配。
首先呢,我们定义一个指代返回值的封闭类 Returned。为什么使用封闭类呢,因为封闭类的子类可查可数。可查可数,也就意味着我们可以有简单的模式匹配。
public sealed interface Returned<T> {
Returned.Undefined UNDEFINED = new Undefined();
record ReturnValue<T>(T returnValue) implements Returned {
}
record Undefined() implements Returned {
}
}
然后呢,我们就可以使用 Returned 来表示返回值了。
public final class FullName {
// snipped
public Returned<String> middleName() {
if (middleName == null) {
return Returned.UNDEFINED;
}
return new Returned.ReturnValue<>(middleName);
}
// snipped
}
最后,我们来看看 Returned 是怎么使用的。
private static boolean hasMiddleName(FullName fullName, String middleName) {
return switch (fullName.middleName()) {
case Returned.Undefined undefined -> false;
case Returned.ReturnValue rv -> {
String returnedMiddleName = (String)rv.returnValue();
yield returnedMiddleName.equals(middleName);
}
};
}
此文章为9月Day16学习笔记,内容来源于极客时间《深入剖析 Java 新特性》