1. 引言

写 Java 代码时,我们经常要判断:某个方法收到 null 参数时,到底该抛 IllegalArgumentException 还是 NullPointerException?这个问题看似小,但在实际开发中高频出现,处理不好容易踩坑。

本文就来深入聊聊这两种选择背后的逻辑,帮你建立清晰的判断标准。我们不搞教条主义,而是结合 Javadoc、JDK 源码习惯和实际调试体验,给出更接地气的建议。

2. 选择 IllegalArgumentException

先看支持抛 IllegalArgumentException 的理由。

下面是一个典型示例:当传入参数为 null 时,手动抛出 IllegalArgumentException

public void processSomethingNotNull(Object myParameter) {
    if (myParameter == null) {
        throw new IllegalArgumentException("Parameter 'myParameter' cannot be null");
    }
    // 正常处理逻辑
}

2.1. 符合 Javadoc 定义

查一下 IllegalArgumentException 的官方文档,它适用于“向方法传递了非法或不合适的参数值”。

✅ 如果你的方法明确要求参数不能为 null,那 null 就是“非法值”,抛 IllegalArgumentException 完全合理。

2.2. 更符合开发者调试直觉

想象你在看线上错误日志。如果看到 NullPointerException,第一反应通常是:哪里空指针解引用了? 你会顺着堆栈往下找 obj.toString()obj.getXXX() 这类调用。

但如果你看到的是 IllegalArgumentException,你会立刻意识到:是调用方传参出问题了。这时候你会直接看调用栈最外层是谁传了 null,定位更快。

✅ 换句话说,IllegalArgumentException 更贴近“参数校验失败”的语义,调试时能更快定位到错误源头。

2.3. 其他支持理由

  • 一致性更好:如果你的方法还会校验其他非法值(比如长度为 0 的字符串、负数等),统一用 IllegalArgumentException 更一致。
  • ⚠️ 有人认为“只有 JDK 才能抛 NullPointerException”,这其实是个误区。Javadoc 并没有这种限制,后面我们也会看到 JDK 自己就在用。

3. 选择 NullPointerException

再来看支持 NullPointerException 的观点。

示例代码如下:

public void processSomethingElseNotNull(Object myParameter) {
    if (myParameter == null) {
        throw new NullPointerException("Parameter 'myParameter' cannot be null");
    }
    // 正常处理逻辑
}

3.1. 也符合 Javadoc 定义

根据 NullPointerException 的文档:

Thrown when an application attempts to use null in a case where an object is required.

翻译一下:当程序在需要对象的地方使用了 null,就应该抛这个异常

✅ 方法参数声明的是引用类型(如 Object myParameter),意味着“这里需要一个对象”,传 null 就违反了这个契约 —— 所以抛 NullPointerException 也没毛病。

3.2. 与 JDK API 保持一致

这是最关键的一点。

JDK 自己就这么干。来看几个例子:

  • Objects.requireNonNull(T obj):传 null 直接抛 NullPointerException
  • ArrayList.addAll(int index, Collection c)
    • index 越界 → IndexOutOfBoundsException
    • c 为 null → NullPointerException

注意:这里没有用 IllegalArgumentException,而是用了更具体的 NullPointerException。说明 JDK 认为 null 是一种特定的非法状态,值得单独用一个异常类型表示

✅ 再看 Guava、Spring 等主流框架,也都倾向于在参数校验时抛 NullPointerException,尤其是配合 Objects.requireNonNull() 时。

4. 结论与建议

这个问题没有绝对正确答案,但可以总结出以下几点实用建议:

✅ 推荐做法

场景 建议
手动校验参数 null **优先抛 NullPointerException**,与 JDK 保持一致
使用 Objects.requireNonNull() 它本身抛 NPE,别包装成 IAE
其他非法参数(如空字符串、非法范围) IllegalArgumentException
团队已有规范 务必保持项目内统一,别混用

✅ 最佳实践示例

public void serviceMethod(String name, Integer id) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }
    if (id == null) {
        throw new NullPointerException("id cannot be null");
    }
    if (name.isEmpty()) {
        throw new IllegalArgumentException("name cannot be empty");
    }
    if (id < 0) {
        throw new IllegalArgumentException("id must be >= 0");
    }
    // 正常业务逻辑
}

或者更简洁地:

public void serviceMethod(String name, Integer id) {
    Objects.requireNonNull(name, "name cannot be null");
    Objects.requireNonNull(id, "id cannot be null");
    // 其他校验...
}

✅ 调试友好提示

无论选哪个异常,一定要在异常信息里带上参数名,比如:

"Parameter cannot be null"
"Parameter 'name' cannot be null"

这样出问题时一眼就知道是哪个参数错了,省去查堆栈的时间。


示例代码已托管至 GitHub:https://github.com/baeldung/core-java-modules/tree/master/core-java-exceptions-3


原始标题:IllegalArgumentException or NullPointerException for a Null Parameter?