使用Objects.requireNonNull(T obj)代替null检查和手动抛出IllegalArgumentException?

19

每当我需要检查方法的给定参数不为空时,我都会编写一个空值检查并在空值检查失败时抛出IllegalArgumentException异常:

    if (user == null) {
        throw new IllegalArgumentException("User can't be null.");
    }

然而,通过阅读一些 Java 8 类的源代码,如 ArrayList,我发现 Oracle 使用 Objects.requireNonNull 来检查参数是否为 null 值,如果测试失败,则抛出 NullPointerException
采用这种方法后,前面的代码片段应该像这样:
Objects.requireNonNull(user, "User can't be null.");

更小和更易读。

假设我控制整个系统的异常处理(即使我不应该有这种控制,有时处理这些未经检查的异常是业务的一部分),我是否应该用 NullPointerException 替换我的 IllegalArgumentException,并使用 Objects.requireNonNull 而不是编写自己的空检查和异常抛出?


15
我们正在JDK中为新代码做这样的事情,并机会适应旧代码。未来JVM有可能会将Objects.requireNonNull本地化,这也是更喜欢使用它的另一个原因。 "我应该使用NPE还是IAE"的辩论大多是无意义的; 两种立场都是可辩护的,而在它们之间争论的大部分努力是浪费的。 - Brian Goetz
3
当Brian Goetz说他要用一种方式做时,很可能那就是你想要使用的方式 ;-). - Daniel
@BrianGoetz,当这些空值检查失败时,我更倾向于采用NullPointerException。 Joshua在他的书中已经表明了对NPE优先于IAE的偏好,并且通过阅读您关于JDK未来的言论,我认为我有足够的证据去那条路。顺便说一句,@OSryx的答案仍然有效,可以实现另一种类型的参数检查。 - Bruno Gasparotto
2
@Daniel 我希望这是真的,但是对于一个有着20年历史和数百个开发人员参与的大型代码库来说,不一致性是不可避免的。但是,这真的重要吗?这些不一致性并不是为了让调用者捕获异常而设计的。更重要的是,你需要_进行任何参数检查_。我担心我们花费的精力更多地是在争论最佳的参数检查方式上,而不是实际去做它。 - Brian Goetz
6
顺便说一句,Objects.requireNonNull() 的 API 允许你在链式的 this() 或者 super() 调用中使用它,例如: super(requireNonNull(x)) - Brian Goetz
2个回答

14
使用 Objects.requireNonNull(c) 是一种非常优雅的方法,可以检查元素是否为 null。但是,关于选择 NullPointerException 还是 IllegalArgumentException 有一个有趣的讨论 --> IllegalArgumentException or NullPointerException for a null parameter?。因此,抛出 NullPointerException 是 java 表示引用为 null 的方式。

否则,您可以创建自己的方法 requireNotNull()。这很简单:

 public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

您可以通过将 NullPointerException 更改为 IllegalArgumentException 来修改异常。


该讨论中排名靠前的答案和这里的答案一样都有一个观点。IllegalArgumentException 看起来更合适,所以我仍然可以将其与我的“自己的版本” Objects.requireNotNull 结合使用,从而抛出我想要的异常。 - Bruno Gasparotto
4
注意,有时候评分最高的答案可能是最早发布的答案。 - user813853
2
你说得对。通过进一步搜索,我发现甚至Joshua Bloch也支持使用NullPointerException而不是IllegalArgumentException,我打开了他的书来确认。现在我明白为什么有时候这被称为“圣战”问题,两种方法都有好处。然而,这个讨论不是这个主题的重点,所以我很快就会接受你的答案。 - Bruno Gasparotto
如果你要自己编写代码,你可能想在参数中添加“@Nullable”,在返回类型中添加“@NotNull”。 - cquezel

7
当方法收到一个不期望的null值时,讨论出现了应该抛出哪种异常。有些人主张使用NullPointerException,而有些人则主张使用IllegalArgumentException。JDK似乎倾向于在这种情况下抛出NullPointerException,这就是为什么Objects.requireNonNull会抛出NullPointerException的原因。
但我不会仅仅因为这个方法而修改现有代码,尽管你可能想考虑在新代码中使用Objects.requireNonNull。(通常使用它使代码更易读,而不是手动检查null并抛出异常。)

2
在我工作的地方,我们创建了自己的 Ensure.notNull(Object val, String msg) 方法,它基本上做的是相同的事情。但是,出于 Hoopje 指出的原因,它会抛出 IllegalArgumentException 而不是 NullPointerException。我们发现这更可取,因为它使得断言的非空参数与意外的 NPXs 明显不同。虽然我还没有在我们的代码库中完成它,但我考虑创建一个新的 NullArgumentException(扩展 IllegalArgumentException)并将其抛出。 - Paul
1
这个"我们发现这更可取,因为它使得断言的非空参数与意外的NPX明显不同。"有点无关紧要 - 当你得到一个NPE时,你也有一个行号,所以在这种特定情况下,你可以看到参数是null的 - 并且Objects.requireNonNull允许你提供一个特定的错误消息,如果你想要的话。 - assylias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接