Java的Error与Exception
今天小明同学来问我一个问题,为什么我们的项目到处在 catch Exception来处理,但却不管Error呢?
我给小明去打开了Error类的说明:
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur. That is, Error and its subclasses are regarded as unchecked exceptions for the purposes of compile-time checking of exceptions.
以及中文翻译:
Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。大多数这样的错误都是异常条件。虽然 ThreadDeath 错误是一个“正规”的条件,但它也是 Error 的子类,因为大多数应用程序都不应该试图捕获它。
在执行该方法期间,无需在其 throws 子句中声明可能抛出但是未能捕获的 Error 的任何子类,因为这些错误可能是再也不会发生的异常条件。
小明读了2遍以后,就若有所悟的样子。然后问了我一个问题:如果我设计一个Error的子类当做我们的业务异常可以吗?
我只能表示:代码上是可以的,但是我会打死你。
Error的设计初衷就是为了表示那些程序自身无法处理的严重错误的,譬如OutOfMemory,只有当内存不足,且JVM无法通过GC释放内存,不得已才抛出的错误。既然JVM已经无法回收空间了,我们捕获了又能干什么呢?不能释放的对象说明我们正在使用,只有通过优化代码逻辑或者增大JVM内存来解决了。
小明又问了我第二个问题,为什么有的Exception要catch,有的不需要呢?
这个算是项目的规范,小明新来不久应该还没学习。我们的原则是,如果能在编码过程中避免的异常,那么久不应该catch,如NullPoint,IndexOutOfBounds,ClassCast等待,如果出错了那么就是我们的代码写的有问题,即使捕获了也无法让程序正常运行。
比如用户增加一个资源,某个字段缺失导致空指针异常,我们捕获了告诉用户异常,用户会把我们赶出去,因为这个字段本来就不是要求非空的,只是我们没去判断而已 😃
什么样的异常我们需要捕获或者显式通过throw声明要求调用者捕获呢?那就是通过代码无法控制,跟运行时的环境有关的异常,譬如IO异常,我们读取磁盘、网络请求等可能会因为文件损坏、丢失、网络异常等原因导致出错,那么这种情况我们就要捕获异常了。等环境恢复后,我们还是可以继续IO操作的。
最后我告诉小明,捕获异常的时候千万不要直接写一个catch(Exception e)
,而是要捕获具体的异常分类处理,你自己想想为什么。