为什么Java同时具有已检查和未检查的异常?

C. *_*oss 5 java theory programming-languages

可能重复:
何时选择已检查和未检查的异常

为什么的Java作为一门语言有两种 checked和unchecked 异常.他们的目的是什么?

注意:我不是在问我何时应该使用它们,或者如何编写它们,而是它们添加到语言中的内容.

Met*_*002 14

检查异常的理论很简单.

在设计接口时,请考虑在方法调用的正常状态下可能发生并将发生的异常情况.在您的界面中声明这些异常,因为程序员必须直接处理它们.

例如,银行账户提款方法可能会声明OverdraftException,这是一个预期的例外 - 提款可能因透支而失败,但客户代码可能会以不同的方式处理此类故障(可能会决定完全拒绝提款,另一个可能决定应用巨额罚款并允许记录负余额,另一个可能决定允许其客户从另一个账户中提取).

但是,运行时异常应该是不应该直接处理的编程错误 - 例如NullPointerExceptions,只有在方法采用无效参数或不直接检查此类情况时才会发生.

这是一个很好的理论.然而,Java搞砸了它的Exceptions实现,并且把这个理论的书推到了窗外.

有两种情况我将说明Java搞乱了Exceptions的实现.这些是IOException和SQLException.

任何时候,Java的IO库中的流都会混乱,从而发生IOException.但是,这是一个经过检查的例外.但是,通常你不能做任何事情,只记录发生错误 - 如果你只是写入控制台,如果你在写入时突然得到IOException,你可以合理地期望做什么?

但还有更多.

IOException还隐藏了文件异常和网络异常等内容.它们可能是为此浮动的IOException的子类,但它仍然是一个经过检查的异常.如果您对外部文件的写入失败,那么您无法真正做到这一点 - 如果您的网络连接被切断,同上.

SQLException也是一样的.异常名称应显示调用它们时发生的情况.SQLException没有.在处理数据库时遇到任何可能数量的错误都会抛出SQLException - 大多数情况都与SQL无关.

因此,程序员通常会对处理异常感到恼火,并让Eclipse(或他们正在使用的任何IDE)生成这样的块:

try {
thisMethodThrowsACheckedExceptionButIDontCare();
}
catch(Exception e) {
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

但是,对于RuntimeExceptions,这些故意冒泡并最终由JVM或容器级别处理.这是一件好事 - 它会强制显示错误然后你必须直接修复代码而不是忽略异常 - 你可能仍然只是打印堆栈跟踪(希望记录它而不是直接打印到控制台),但是然后会有一个异常处理程序,你因为一个真正的问题而被迫写入 - 不是因为一个方法说它可能会抛出异常,而是它会这样做.

Spring使用DataAccessException来包装SQLExceptions,这样您就不必将它们作为已检查的异常处理.它使代码更加清晰 - 如果你期望DataAccessException,你可以处理它 - 但是大多数时候你让它传播并记录为错误,因为你的SQL应该在你发布应用程序时调试,意味着DataAccessException可能是您无法解决的硬件问题 - DataAccessException是一个比SQLException更有意义的名称,因为它表明对数据的访问失败 - 而不是您的SQL查询错误.


Ale*_*äll 5

它们区分了图书馆设计师必须抓住的错误和他们认为程序员不应该处理的错误.

例如,程序处理来自用户的错误输入可能是合理的,但如果底层操作系统出现问题并且线程开始无故死亡,那么程序应该不应该处理.

  • 不幸的是,这个论点在实践中失败了——请看我关于 IOException 和 SQLException 的回答……Java 的库搞砸了区别,一切都从那里走下坡路…… (2认同)

Kev*_*ose 5

就个人而言,我认为已检查的异常是Java中的一个错误.

除此之外,指定已检查和未检查的异常允许库区分可恢复和不可恢复的错误.通过使所有可恢复的错误抛出已检查的异常,库/语言可以强制开发人员处理他们可能以其他方式结束的边缘情况.

这个问题很大:

try{
  myCode();
}catch(Exception e){ //Do nothing }
Run Code Online (Sandbox Code Playgroud)

此外,在大多数情况下,最好只举手并在发生异常时将异常传递出去.通过强制声明已检查的异常,一个真正不关心是否发生错误的方法最终会产生依赖性(在兼容性方面,但在代码嗅觉和其他方面),它实际上不应该.