我应该显式抛出NullPointerException还是让Java为我做?

时间:2011-10-17 12:43:32

标签: java null nullpointerexception

正如标题所说,我想知道关于抛出NullPointerExceptions的最佳做法是什么。具体来说,如果我有一个外部库函数,可以在我不想实际处理的情况下返回null(参见下面的具体示例),因为null表示软件有问题。问题是,我应该

  1. 检查null的返回值并自行抛出NullPointerException,或
  2. 一旦我尝试使用该对象,我应该让Java为我做脏工作。
  3. 第一种方法让我添加一些额外的信息,因为我构建了NullPointerException,但是第二种方法在我看来更清晰的代码。我还想知道任何性能影响,也就是说,Java在“原生”投掷NPE方面更有效率吗?

    举例来说,我正在尝试使用Java Speech API使用以下代码创建语音合成器:

    synthesizer = Central.createSynthesizer(generalDesc);
    
    if (synthesizer == null) {
        // (1) throw NPE explicitly
        throw new NullPointerException("No general domain synthesizer found.");
    }
    
    // (2) let the JVM throw the NPE when dereferencing
    synthesizer.allocate();
    

    Central.createSynthesizer如果找不到合适的合成器,则返回null,这通常是由于缺少speech.properties文件引起的。所以这是系统设置错误的问题,而且在运行时很难恢复,而不是需要以编程方式处理的情况。因此,我认为抛出NullPointerException是一个有效的响应,因为它表示一个错误(不在代码中,而是在软件的部署中)。但是由于synthesizer对象在下一个语句中被解除引用,我应该让JVM为我抛出NPE并保存空检查吗?

    附录:考虑到当jVM启动时,speech.properties 被加载需要存在于(通常)“user.home”或“java.home”中的文件系统上/ lib“,令人费解的是createSynthesizer没有直接抛出一个NPE(这是我最初在弗洛伊德语中写的)当它找不到它但返回null时。我认为抛出NullPointerException是正确的做法,因为它表明了软件部署中的实际错误。

6 个答案:

答案 0 :(得分:8)

我要说你永远不应该明确创建NullPointerException而是使用更清楚地描述情况的异常类型。在你的情况下,我会说IllegalStateException符合“错误的系统设置,并且在运行时非常难以恢复”的情况。或者您可以创建自己的ComponentMissingException。如果所需方法参数为null,则通常使用IllegalArgumentException

答案 1 :(得分:8)

在你的情况下:都没有。检查null并抛出更有意义的异常,而不是NPE。

一般情况下 - 如果NPE不应该发生,不要明确地测试它,Java会为你做。编写的测试较少,读取的代码较少,分析的复杂性较低。

但是,如果null预计会尽快测试并进行相应的解释。否则NullPointerException稍后会在不同的行/方法中出现,这使得调试真正的问题变得更加困难。

答案 2 :(得分:2)

我不希望 null 成为有效的返回值,即使在“特殊情况下”也是如此。所以我采取了另一种方法。

在你的情况下,我用 @NotNull 注释方法 createSynthesizer(...)(@NotNull是惊人的注释) 。只要 createSynthesizer(...)想要返回 null ,我就会得到 IllegalStateException 而不是NPE。

你会得到:

java.lang.IllegalStateException: @NotNull method .../.../createSynthetiser(...) must not return null

这种方法有几个好处:

  • NullPointerException IllegalStateException 扩展 RuntimeException ,因此您不会从根本上改变您的程序

  • 异常应立即抛出错误发生的地方(一旦你自己检查/抛出或尝试取消引用 null ,就会发生错误)

  • 您不再需要打扰 if ... == null / throw 部分了。

作为一个巨大的,额外的好处,一些IDE(如IntelliJ IDEA)将实时警告您可能的 @NotNull 违规行为。

答案 3 :(得分:1)

关于原始代码:

synthesizer = Central.createSynthesizer(generalDesc);

if (synthesizer == null) {
    // (1) throw NPE explicitly
    throw new NullPointerException("No general domain synthesizer found.");
}

// (2) let the JVM throw the NPE when dereferencing
synthesizer.allocate();

我的看法是抛出这里显示的NPE是可以的,但有很多警告。只有当NPE ctor参数是一个充分描述性(并且希望是唯一的)消息(希望从一个常量或资源集中拉出来)时,这是可以接受的警告。另一个警告是,你的主要优先事项是将事情从门,这样的情况,这将被视为一个可接受的快速解决方案。

在理想情况下,我的偏好是使用特定于无效配置的例外。当那些不可用时,要么使用NPE子类(如Apache Commons Math的NullArgumentException),要么使用Apache Common Lang 2.x中的旧例外。这是我对NPE和IllegalArgument类型例外的立场。我不一定同意Apache Common Lang的position更喜欢使用标准JDK异常而不是更语义相关的异常。但那只是我,而我正在走下正轨......

......回到最初的问题。正如我之前所说的那样,以这种方式投掷NPE就好了(当你在其中一个“需要得到它时!(10 + 1)”那种情况。

请注意,这是由应用程序或系统配置问题引起的NPE,因为您正确识别它。也就是说,NPE不是另一个错误条件的症状或影响的根本原因(在这种情况下,是配置或环境错误。)

  

如果找不到合适的,Central.createSynthesizer将返回null   合成器,通常是由于缺少speech.properties引起的   文件。所以这是一个错误的系统设置问题,而且很漂亮   在运行时不可恢复,而不是需要的情况   以编程方式处理。

不可恢复性不确定。应用程序可以通过其他方式以编程方式处理此情况。

  

因此,我相信扔一个   NullPointerException是一个有效的响应,因为它表示一个错误   (不在代码中,而是在软件的部署中)。但自从   应该在下一个语句中取消引用合成器对象   我只是让JVM为我抛出NPE并保存空检查?

我不会这样做,即使在 get-that-sh1t-out-of-the-door 情况下也是如此。 JVM以这种方式抛出的NPE将会有一个非常无意义的消息。一般情况下,检查所有内容是否为NULL,并在遇到一个 描述性 异常(NPE或其他)时抛出。

如果您能够保证已经检查过NPE(已经按照合同设计的方式),那么不要检查NPE。

  

附录:考虑在JVM时加载speech.properties   开始需要存在于(通常)“user.home”或文件系统中   “java.home / lib”,令人费解的是createSynthesizer没有   直接抛出一个NPE(这是我原来写的一个   弗洛伊德滑动)当它找不到但返回null时。

同样,那是因为对该情况的响应是特定于应用程序的。应用程序可能决定使用部分功能进行 limping 模式,而不是崩溃并烧毁到地面。如果createSynthesizer抛出一个NPE,那么API设计者会强制应用程序设计者采用后面的行为,或者更长的时间来实现“limping”操作模式(通过必须使用catch / try而不是简单的if-null测试。

  

我认为抛出NullPointerException是正确的做法   这里,因为它表示部署中的实际错误   软件

同样,只有当NPE是一个快速肮脏的解决方案才能让事情摆脱困境。在这种情况下,没关系。更好的方法是确定这是什么,配置错误。

因此,最好有特定于应用程序的异常,例如 IllegalConfigurationException InvalidConfigurationException IncompleteConfigurationException 。我不喜欢在这种情况下使用java.lang.IllegalStateException,因为这不是因为调用处于无效状态的东西而引起的。由于配置无效,达到了无效状态。也许我正在玩语义游戏,但在这种情况下使用IllegalStateException有点不对劲(我知道这只是我主观的。)

答案 4 :(得分:0)

非常有趣的问题。

我认为该方法应抛出某种ProblemCreatingSynthesizerException,而不是返回null。

我会把null检查并抛出你自己的NPE或其他自定义ProblemWithSynthesizerException(由于某种原因,Sun将此异常视为JVM-ish异常,并不打算由程序员使用这就是它在一些认证教程和书中所说的内容。但是,我不买,有些经常把我自己的NPE放在我的库中。)

答案 5 :(得分:0)

我从未使用过Java,但如果我使用的是应用程序,我希望看到错误消息而不是崩溃。 NullPointerException听起来像代码中的错误 - 我宁愿看到一条错误消息,其中包含有关如何正确配置程序的说明,或者至少是指向具有此类指示的网页的超链接。

如果我是一个用户并且看到一个程序因NullPointerException而终止,我会提交一个针对该程序的错误,或者至少对下一步该做什么感到困惑。