我发现自己忙着重构我的宠物项目,并删除与异常抛出声明相关的所有噪音.基本上,违反条件的一切都是断言违规,或者正式地说,AssertionError,在Java中慷慨地允许从方法的签名中省略.我的问题是:拥有Exceptions层次结构有什么意义?我的经验是每个例外都是独一无二的,并且没有正式的标准来确定一组例外是另一组的子集.即使是已检查和未检查的异常之间的区别也是模糊的,例如,当懒惰(或不耐烦)的程序员可以轻松地将其包装到RuntimeException中并重新抛出它时,为什么我会坚持客户端代码捕获异常?
JUS*_*ION 11
从理论上讲,Java异常层次结构具有一定的意义:
Throwable*
-> Error (OutOfMemoryError, etc.)
-> Exception (IOException, SQLException, etc.)
-> RuntimeException (IndexOutOfBoundsException, NullPointer, etc.)
Run Code Online (Sandbox Code Playgroud)
现在,这些背后的理论实际上具有一定的意义.(遗憾的是,由于累积的残骸,实际的实施还有待改进.)
Error-descended Throwable对象是程序预计无法从中恢复的严重错误.(换句话说,你通常不会抓住这些.)其中一个突然出现是一个严重的整体系统问题.例如,当你的内存不足时,这代表了一个严重的失败,因为从理论上讲,GC现在拼命地试图为你腾出空间.抓住这一点毫无意义.
Exception-descended Throwable对象是程序在正常操作期间可合理预期会遇到的所有错误; 诸如网络错误,文件系统错误等等.确实除了那些后代之外RuntimeException,它们被强制要求程序明确地处理这些错误 - 它们就是所谓的"检查异常".(当然,糟糕的程序员会通过将其删除来"处理"这些,但这是程序员问题,而不是系统问题.)
RuntimeException-descended Throwable对象略有不同.它们是错误,不一定是预期的,但程序可以从它们发生时合理地恢复.因此,他们没有被检查(程序没有义务处理这些),但如果有合理的方法来处理这种情况,他们可能会这样做.通常,这些异常表示某种编程错误(与之前的类别相反,这是在正常操作中发生的预期错误).
这种层次结构是否有意义?好吧,在某种程度上它似乎. Error被系统抛出,代表了一个可能会破坏你的程序的重大失败. RuntimeException,如果使用得当,系统库(或偶尔由你自己的程序)抛出,通常意味着有人搞砸了某个地方,但没关系,因为你可以从中恢复.其他Exception对象是预期的错误,实际上是对象的声明接口的一部分.
但...
最后一项是问题所在.直截了当地说,检查的例外是躯干解剖结构下部的严重疼痛.他们不必要扰乱了异常处理的样板代码以这样的方式来呈现,在我看来(和许多其他我要补充!),整点异常的实际意义:错误检测和错误处理的分离.通过强制链中的每个方法来处理异常 - 即使它只是为了重新包装它并传递它! - 代码变得混乱了错误处理的细节,以至于它比返回状态代码和处理后更好一点.每个方法调用.
如果Java是一种更智能的编程语言,则在编译/链接时检查已检查的异常,以查看它们是否在系统范围内正确处理,而不是在每个类文件中的每个方法调用中.不幸的是,Java的整个架构不允许这种级别的整个程序分析,结果是,在我看来(但许多人再次分享),实际上是异常处理和错误返回两个世界中最糟糕的混合:你获取显式错误返回的大部分样板脚手架,但您也得到COME FROM异常的类似行为.