NPE 或许是编程语言中最常见的问题,被 Null 的发明者托尼·霍尔(Tony Hoare)称之为十亿美元的错误。在 Java 中并没有内置的处理 Null 值的语法,但仍然存在一些相对优雅的方式能够帮助我们的规避 NPE。
一.使用 JSR-305/jetbrain 等注解
NotNull
Nullable

通过在方法参数、返回值、字段等位置显式标记值是否可能为 Null,配合代码检查工具,能够在编码阶段规避绝大部分的 NPE 问题,建议至少在常用方法或者对外 API 中使用该注解,能够对调用方提供显著的帮助。
二.用 Optional 处理链式调用
Optional 源于 Guava 中的 Optional 类,后 Java 8 内置到 JDK 中。Optional 一般作为函数的返回值,强制提醒调用者返回值可能不存在,并且能够通过链式调用优雅的处理空值。
public class OptionalExample {
public static void main(String[] args) {
// 使用传统空值处理方式
User user = getUser();
String city = "DEFAULT";
if (user != null && user.isValid()) {
Address address = user.getAddress();
if (adress != null) {
city = adress.getCity();
}
}
System.out.println(city);
// 堆代码 duidaima.com
// 使用 Optional 的方式
Optional<User> optional = getUserOptional();
city = optional.filter(User::isValid)
.map(User::getAddress)
.map(Adress::getCity)
.orElse("DEFAULT")
System.out.println(city);
}
@Nullable
public static User getUser() {
return null;
}
public static Optional<User> getUserOptional() {
return Optional.empty();
}
@Data
public static class User {
private Adress address;
private boolean valid;
}
@Data
public static class Address {
private String city;
}
}
三.用 Objects.equals(a,b) 代替 a.equals(b)
equals方法是 NPE 的高发地点,用 Objects.euqals来比较两个对象,能够避免任意对象为 null 时的 NPE。
四.使用空对象模式
空对像模式通过一个特殊对象代替不存在的情况,代表对象不存在时的默认行为模式。常见例子:
用 Empty List 代替 null,EmptyList 能够正常遍历:
public class EmptyListExample {
public static void main(String[] args) {
List<String> listNullable = getListNullable();
if (listNullable != null) {
for (String s : listNullable) {
System.out.println(s);
}
}
List<String> listNotNull = getListNotNull();
for (String s : listNotNull) {
System.out.println(s);
}
}
@Nullable
public static List<String> getListNullable() {
return null;
}
@NotNull
public static List<String> getListNotNull() {
return Collections.emptyList();
}
}
空策略
public class NullStrategyExample {
private static final Map<String, Strategy> strategyMap = new HashMap<>();
public static void handle(String strategy, String content) {
findStrategy(strategy).handle(content);
}
@NotNull
private static Strategy findStrategy(String strategyKey) {
return strategyMap.getOrDefault(strategyKey, new DoNothing());
}
public interface Strategy {
void handle(String s);
}
// 堆代码 duidaima.com
// 当找不到对应策略时, 什么也不做
public static class DoNothing implements Strategy {
@Override
public void handle(String s) {
}
}
}