陷阱 - 使用正常流程控制的异常
有一些 Java 专家不会背诵的口头禅:
“异常情况只应用于特殊情况。”
(例如: http : //programmers.stackexchange.com/questions/184654 )
其实质是使用异常和异常处理来实现正常的流控制是一个坏主意(在 Java 中)。例如,比较这两种处理可能为 null 的参数的方法。
public String truncateWordOrNull(String word, int maxLength) {
if (word == null) {
return "";
} else {
return word.substring(0, Math.min(word.length(), maxLength));
}
}
public String truncateWordOrNull(String word, int maxLength) {
try {
return word.substring(0, Math.min(word.length(), maxLength));
} catch (NullPointerException ex) {
return "";
}
}
在这个例子中,我们(通过设计)处理 word
是 null
的情况,好像它是一个空单词。这两个版本使用传统的 if … else 和或者 try … catch 来处理 null
。我们该如何决定哪个版本更好?
第一个标准是可读性。虽然可读性难以客观量化,但大多数程序员都同意第一版的基本含义更容易辨别。实际上,为了真正理解第二种形式,你需要明白 NullPointerException
或 String.substring
方法不能抛出 NullPointerException
。
第二个标准是效率。在 Java 8 之前的 Java 版本中,第二个版本比第一个版本慢很多(数量级)。特别是,异常对象的构造需要捕获和记录堆栈帧,以防万一需要堆栈跟踪。
另一方面,在许多情况下,使用异常比使用条件代码处理异常事件更具可读性,更高效和(有时)更正确。实际上,在极少数情况下有必要将它们用于非特殊事件; 即相对频繁发生的事件。对于后者,值得研究减少创建异常对象的开销的方法。