我应该显式抛出 NullPointerException 还是让 Java 帮我处理?
正如标题所示,我想知道关于抛出 NullPointerExceptions 的最佳实践是什么。具体来说,如果我有一个外部库函数,它可以在我不想实际处理的情况下返回 null
(请参阅下面的具体示例),如 null
表明软件有问题。问题是,我应该
- 检查
null
的返回值并自己抛出 NullPointerException,还是 - 应该在我尝试使用该对象时让 Java 为我做这些肮脏的工作。
第一种方法让我添加一些额外的信息,因为我可以构造 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
,这通常是由于缺少peer.properties 文件引起的。因此,这是系统错误设置的问题,并且在运行时几乎无法恢复,而不是需要以编程方式处理的情况。因此,我相信抛出 NullPointerException 是一个有效的响应,因为它表明存在错误(不是在代码中,而是在软件的部署中)。但由于 synthesizer
对象在下一个语句中被取消引用,我是否应该让 JVM 为我抛出 NPE 并保存 null 检查?
附录:考虑到speech.properties 在 JVM 启动时加载 需要存在于文件系统上(通常)“user.home”或“java.home/lib”中,令人费解的是,当 createSynthesizer
找不到它时,它并没有直接抛出 NPE(这是我最初在 Freudian slip 中编写的内容),而是返回 null。我认为在这里抛出 NullPointerException 是正确的做法,因为它表明软件部署中存在实际错误。
As the title says, I am wondering what the best practice is regarding the throwing of NullPointerExceptions. Specifically, if I have an external library function that can return null
in circumstances that I don't want to actually handle (see below for a specific example), as the null
indicates a problem with the software. The question is, should I
- check the return value for
null
and throw the NullPointerException myself, or - should I just let Java do the dirty work for me as soon as I try to use the object.
The first approach lets me add some additional information, since I get to construct the NullPointerException, but the second makes for cleaner code in my opinion. I would also wonder as to any performance implications, that is, is Java more efficient at throwing the NPE "natively"?
By way of example, I am trying to use the Java Speech API to create a speech synthesizer using the following code:
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
returns null
if it cannot find a suitable synthesizer, which is most often caused by a missing speech.properties file. So it's a matter of wrong setup of the system, and pretty unrecoverable from at runtime, rather than circumstances that need to be handled programmatically. As such, I believe throwing a NullPointerException is a valid response, since it indicates a bug (not in the code but in the deployment of the software). But since the synthesizer
object is dereferenced in the very next statement, should I just let the JVM throw the NPE for me and save the null check?
Addendum: Considering that speech.properties gets loaded when the JVM starts needs to exist on the filesystem in (normally) "user.home" or "java.home/lib", it is puzzling that createSynthesizer
doesn't straight up throw an NPE (which is what I had written originally in a Freudian slip) when it fails to find it but returns null instead. I think that throwing a NullPointerException is the right thing to do here, because it indicates an actual bug in the deployment of the software.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我从未使用过 Java,但如果我使用该应用程序,我希望看到错误消息而不是崩溃。 NullPointerException 对我来说听起来像是代码中的错误 - 我宁愿看到一条错误消息,其中包含有关如何正确配置程序的说明,或者至少是指向具有此类说明的网页的超链接。
如果我是一名用户,看到一个程序因 NullPointerException 而终止,我会针对该程序提交一个错误,或者至少对下一步该做什么感到困惑。
I have never used Java, but if I were using the application, I would want to see an error message than a crash. NullPointerException sounds like a bug in the code to me - I would rather see an error message with directions on how to properly configure the program, or at least a hyperlink to a web page that had such directions.
If I were a user and saw that a program had terminated with NullPointerException, I would file a bug against the program, or at least be confused as to what to do next.
就你而言:两者都不是。检查
null
并抛出更有意义的异常,而不是 NPE。一般来说,如果 NPE 不应该发生,就不要显式地测试它,Java 会为你做这件事。编写的测试更少,阅读的代码更少,分析的复杂性更低。
但是,如果需要
null
,请尽快对其进行测试并进行相应的解释。否则NullPointerException
稍后会在不同的行/方法中的某个地方发生,从而使调试真正的问题变得更加困难。In your case: neither. Check for
null
and throw more meaningful exception, not NPE.In general - if NPE should not occur, don't test for it explicitly, Java will do it for you. Less tests to write, less code to read, less complexity to analyze.
However if
null
is expected test it as soon as possible and interpret accordingly. OtherwiseNullPointerException
will occur somewhere later in different line/method, making it harder to debug the real problem.我想说的是,您永远不应该显式创建 NullPointerException,而应使用更清楚地描述情况的异常类型。就您而言,我想说
IllegalStateException
适合“系统设置错误,并且在运行时几乎无法恢复”的情况。或者您可以创建自己的 ComponentMissingException。如果所需方法参数为null
,则通常使用IllegalArgumentException
。I'd say that you should never explicitly create a
NullPointerException
and instead use an exception type that more clearly describes the situation. In your case, I'd sayIllegalStateException
would fit the situation "wrong setup of the system, and pretty unrecoverable from at runtime". Or you could create your ownComponentMissingException
. In cases where a required method parameter isnull
,IllegalArgumentException
is typically used.我不喜欢让 null 成为有效的返回值,即使在“特殊情况”下也是如此。所以我采取了另一种方法。
在您的情况下,我将使用 @NotNull 注释方法 createSynthesizer(...) (@NotNull 是一个令人惊叹的注释)。一旦createSynthesizer(...)想要返回null,我就会得到一个IllegalStateException,而不是NPE。
你会得到:
这种方法有几个好处:
NullPointerException和IllegalStateException都扩展了RuntimeException,所以你从根本上来说不是更改您的程序
异常应在错误发生的地方立即抛出(不是稍后,一旦您检查/抛出自己或一旦您尝试取消引用null)
您无需费心编写if ... == null / throw 部分
作为一个巨大的附加好处,某些 IDE(例如 IntelliJ IDEA)会实时警告您可能的 @NotNull 违规行为。
I dont like having null be a valid return value, even in "exceptional circumstances". So I take yet another approach.
In your case I'd annotate the method createSynthesizer(...) with @NotNull (@NotNull is an amazing annotation). Instead of an NPE, I'd get an IllegalStateException as soon as createSynthesizer(...) would want to return null.
You'd get a:
There are several benefits to this approach:
both NullPointerException and IllegalStateException extends RuntimeException so you're not fundamentally changing your program
the exception shall be thrown immediately where the error happens (not later on, once you either check/throw yourself or once you try to dereference null)
you don't need to bother writing the if ... == null / throw part anymore.
As a, gigantic, added benefit some IDE (like IntelliJ IDEA) will warn you in real-time about probable @NotNull violations.
关于原始代码:
我的看法是,抛出此处所示的 NPE 是可以的,但有很多警告。唯一需要注意的是,只有当 NPE 构造函数参数是一个足够描述性(并且希望是唯一的)消息(希望从常量或资源集中拉出的消息)时才可以。另一个警告是,您的主要优先事项是从 NPE 构造函数中获取内容。门,以及这样的情况,这将被视为可接受的快速解决方案。
在理想情况下,我的偏好是使用特定于无效配置的异常。当这些不可用时,可以使用 NPE 子类(例如 Apache Commons Math 的 NullArgumentException) 或 Apache Common Lang 2.x。这就是我对 NPE 和 IllegalArgument 类型异常的立场。我不一定同意 Apache Common Lang 的立场,即更喜欢使用标准 JDK 异常超过语义相关的异常。但这只是我,我已经偏离了正题……
所以回到最初的问题。正如我之前所说,以一种快速而肮脏的方式扔掉 NPE 是可以的(当你处于其中之一时“需要把那个屎拿出来!!(10+1)” 。
但请注意,这是由应用程序或系统配置问题引起的 NPE,正如您正确识别的那样,也就是说,NPE 不是其他错误情况的症状或影响所导致的 情况下,配置或环境错误。)
不可恢复性并不是确定的。应用程序可以有其他方法以编程方式处理这种情况。
我不会这样做,即使在get-that-sh1t-out-of-the-door情况下。 JVM 以这种方式抛出的 NPE 中将包含一条非常无信息的消息。一般来说,检查所有内容是否为 NULL,并在遇到异常时抛出描述性异常(NPE 或其他)。
如果您可以保证您所获得的任何内容(例如参数)已经检查过 NPE(以合同设计的方式),则不要检查 NPE。
同样,这是因为对这种情况的响应是特定于应用程序的。应用程序可能会决定进入具有部分功能的跛行模式,而不是崩溃并烧毁。如果
createSynthesizer
抛出一个NPE,那么API设计者会强制应用程序设计者采用稍后的行为,或者花更多的时间来实现“跛行”模式操作(必须使用 catch/try 而不是简单的 if-null 测试。再次强调,前提是 NPE 是一种快速解决方案,可以让事情顺利进行。在这些条件下,就可以了。更好的方法是确定这是什么,配置错误。
因此,最好有特定于应用程序的异常,例如 IllegalConfigurationException 或 InvalidConfigurationException 或 IncompleteConfigurationException。我不喜欢在这种情况下使用 java.lang.IllegalStateException ,因为这不是由调用无效状态的内容引起的。由于配置无效而达到无效状态。也许我正在玩语义游戏,但在这种情况下使用 IllegalStateException 有点令人讨厌(我知道这只是我的主观看法。)
Regarding the original code:
My take is that throwing the NPE as shown here is OK, but with tremendous caveats. The caveat under which this is OK is only if the NPE ctor argument is a sufficiently descriptive (and hopefully unique) message (one hopefully pulled out of a constant or resource set.) Another caveat is that your main priority to get things out of the door, and such casea, this would count as an acceptable quick-n-dirty solution.
Under ideal circumstances, my preference is use exceptions specific to invalid configurations. And when those are not available, to either use NPE subclasses (like Apache Commons Math's NullArgumentException) or the old exceptions found in Apache Common Lang 2.x. That is my position for NPEs and IllegalArgument-type exceptions. I don't necessarily agree with Apache Common Lang's position on preferring to use the standard JDK exceptions over more semantically-relevant exceptions. But that's just me, and I'm getting off the tangent...
... so back to the original question. As I said before, throwing the NPE like that is ok in a quick-n-dirty way (when you are in one of those "need to get that sh1t out!!(10+1)" kind of situations.
Notice, however, this is a NPE caused by an application or systems configuration problem, as you correctly identified it. That is, the NPE is not the root cause, by a symptom or effect of another error condition (in this case, a configuration or environment error.)
Unrecoverability is not a certainty. An application could have other ways to handle this situation programmatically.
I wouldn't do that, even under get-that-sh1t-out-of-the-door circumstances. The NPE thrown that way by the JVM will have a very uninformative message in it. In general, check everything for NULL and throw a descriptive exception (NPE or otherwise) when you encounter one.
Don't check for NPEs if you can guarantee that whatever you are getting (parameters for example) has already been checked for NPEs already (in a design-by-contract kind of way.)
Again, that's because the response to that situation is application specific. The application might decide to go on a limping mode with partial functionality instead of crashing and burning to the ground. If
createSynthesizer
were to throw a NPE, then the API designer forces the application designer to adopt the later behavior, or go to somewhat greater lengths to implement a "limping" mode of operations (by having to use a catch/try instead of a simple if-null test.Again, only if the NPE is a quick-n-dirty solution to get things out of the door. Under those conditions, it is ok. A better approach is to identify what this is, a configuration error.
So it would be better to have application specific exceptions like IllegalConfigurationException or InvalidConfigurationException or IncompleteConfigurationException. I don't like using
java.lang.IllegalStateException
for such cases, because this is not caused by calling something in an invalid state. The invalid state got reached because of an invalid configuration. Maybe I'm playing semantic games, but there is something icky about using IllegalStateException in such cases (that's just me being subjective, I know.)非常有趣的问题。
我认为该方法应该抛出某种
ProblemCreatingSynthesizerException
,而不是返回 null。我会进行空检查并抛出一个 NPE 或您自己的其他自定义
ProblemWithSynthesizerException
(Sun,出于某种原因,将此异常视为 JVM 式异常,不打算由程序员使用这是一些认证教程和书籍中所说的内容,但我并不买账,而且我经常将自己的 NPE 扔进我的库中。Very interesting question.
I think some kind of
ProblemCreatingSynthesizerException
should be thrown by that method, instead of returning null.I'd put the null check and throw a NPE or other custom
ProblemWithSynthesizerException
of your own (Sun, for some reason, conceived this Exception as a JVM-ish exception, not meant to be used by the programmer. This is what it says in some certification tutorials and books. However, I don't buy that, and some often I throw my own NPEs in my libraries).