关于原始代码:
synthesizer = Central.createSynthesizer(generalDesc);
if (synthesizer == null) {
throw new NullPointerException("No general domain synthesizer found.");
}
synthesizer.allocate();
我认为按照这里所示的方式抛出NPE是可以的,但需要极大的注意事项。只有在NPE构造函数参数足够描述性(并且希望是唯一的)消息(最好是从常量或资源集中提取的消息)的情况下才可以这样做。另一个警告是你的主要优先事项是让事情完成,如果情况如此,那么这将算作一种可接受的快速解决方案。
在理想情况下,我的首选是使用特定于无效配置的异常。当这些不可用时,要么使用NPE子类(例如Apache Commons Math的NullArgumentException),要么使用Apache Common Lang 2.x中找到的旧异常。这是我对NPE和IllegalArgument类型异常的立场。我并不一定同意Apache Common Lang关于更喜欢使用标准JDK异常而不是更语义相关的异常的position。但这只是我的看法,我要结束这个话题了...
...所以回到最初的问题。正如我之前所说,像这样抛出NPE在快速而肮脏的方式下是可以的(当你处于那种“需要把那些狗屎搞定!!(10+1)”的情况下)。
然而,请注意,这是由应用程序或系统配置问题引起的NPE,正如您正确地识别的那样。也就是说,NPE不是根本原因,而是另一个错误条件的症状或影响(在这种情况下,是配置或环境错误)。
如果Central.createSynthesizer找不到合适的语音合成器,则返回null,这往往是由于缺少speech.properties文件引起的。因此,这是系统设置错误,而且在运行时相当难以恢复,而不是需要以编程方式处理的情况。
无法恢复并不是一定的。应用程序可能有其他方法来以编程方式处理这种情况。
因此,我认为抛出NullPointerException是一个有效的响应,因为它表示存在错误(不在代码中,而是在软件部署中)。但由于合成器对象在下一条语句中被取消引用,所以我应该让JVM为我抛出NPE并保存空检查吗?
即使在“快点把这个东西拿出去”的情况下,我也不会这样做。JVM抛出的NPE将具有非常不具信息性的消息。通常,在遇到NULL时检查所有内容并抛出一个描述性异常(NPE或其他异常)。
如果您可以保证已经检查了任何您正在获取的内容(例如参数),请不要检查NPE(以设计契约的方式)。
附加说明:考虑到 JVM 加载 speech.properties 文件时需要存在于文件系统中(通常是“user.home”或“java.home/lib”),当 createSynthesizer 方法无法找到该文件时,它没有直接抛出 NPE(这是我最初由于口误写下的内容),而是返回 null,这令人困惑。
再次强调,这是因为对于这种情况的响应是特定于应用程序的。应用程序可能决定进入部分功能的“跛脚”模式,而不是崩溃。如果 createSynthesizer 抛出 NPE,则 API 设计者会强制应用程序设计者采用后一种行为,或者更费力地实现“跛脚”操作模式(通过使用 catch/try 而不是简单的 if-null 测试)。
我认为在这里抛出 NullPointerException 是正确的做法,因为它表示软件部署中的实际错误。
同样地,只有在 NPE 是快速解决问题的临时方案时才是可以的。在这些条件下,它是可以接受的。更好的方法是识别这是一个配置错误。
因此,最好使用特定于应用程序的异常,例如IllegalConfigurationException、InvalidConfigurationException或IncompleteConfigurationException。我不喜欢在这种情况下使用java.lang.IllegalStateException
,因为这不是由于在无效状态下调用某些内容引起的。无效状态是由于无效配置而达到的。也许我在玩语义游戏,但在这种情况下使用IllegalStateException有点棘手(我知道这只是我的主观看法)。
Central
类会在"user.home"或"java.home/lib"中寻找speech.properties文件,而不是从参数中获取位置。这通常作为安装语音引擎的一部分来完成,因此实际上是一个部署问题。IllegalStateException
可能确实是适当的,但我也想看看对于首次出现该异常时如何处理的共识是什么。在我的观点中,抛出IllegalStateException
就是在处理它,因为我必须积极地编写代码来处理它,而不是只让JVM抛出NPE。 - ThomasH