在 Java 开发中,NullPointerException(空指针异常)恐怕是出现频率最高的运行时异常。它很少是思考出来的,多数是在日志里突然蹦出来。下面从几个常见场景出发,看看它通常是怎么发生的,以及如何从源头避免。

一、典型成因

1. 调用对象的方法或访问其属性

String name = getUser().getName(); // getUser() 返回 null
System.out.println(name.length()); // 抛 NullPointerException

2. 数组或集合元素为 null

String[] arr = new String[10];
arr[0].isEmpty(); // arr[0] 为 null

3. 自动拆箱(unboxing)

Integer count = null;
int size = count; // 空 Integer 拆箱为 int 时抛异常

4. 从 Map 直接取值后强转

String val = (String) map.get("key"); // key 不存在时得到 null

二、解决思路

1. 使用 Optional 让空值显性化

Java 8 引入的 Optional 能强制调用方去考虑「可能为空」的情况:

Optional<User> user = Optional.ofNullable(getUser());
String name = user.map(User::getName).orElse("未知用户");

2. 对象方法入参使用 Objects.requireNonNull

在方法入口校验参数,让异常在最早时刻以清晰的信息暴露:

public void process(User user) {
    Objects.requireNonNull(user, "user 不能为 null");
    // 正常业务逻辑
}

3. 防御式判断

if (user != null && user.getName() != null) {
    System.out.println(user.getName());
}

注意:&& 左侧为 false 时不会再执行右侧,所以这种写法是安全的。

三、小结

  • 空指针的根源是「对可能为 null 的值不做检查就使用」。
  • 良好的习惯:外部数据(数据库查询、接口返回、参数)一律假设可能为 null。
  • 能用 Optional / Objects.requireNonNull 的地方优先使用,让空值成为显式的约定。
  • 避免返回 null:定义返回空集合 Collections.emptyList() 而不是 null,可以消灭一大类空指针。