2023年11月29日发(作者:)

如何处理异常?catchExceptionORcatchThrowable

Java中,当你需要统⼀处理异常的时候,你是会选择catch (Exception),还是直接catch (Throwable)

Java的异常体系

Throwable: Java中所有异常和错误类的⽗类。只有这个类的实例(或者⼦类的实例)可以被虚拟机抛出或者被javathrow关键字抛

出。同样,只有其或其⼦类可以出现在catch⼦句⾥⾯。

Error: Throwable的⼦类,表⽰严重的问题发⽣了,⽽且这种错误是不可恢复的。

Exception: Throwable的⼦类,应⽤程序应该要捕获其或其⼦类(RuntimeException例外),称为checked exception。⽐如:

IOException,

RuntimeException: Exception的⼦类,运⾏时异常,程序可以不捕获,称为unchecked exception。⽐如:NullPointException.

应该catch什么

其实只要是Throwable和其⼦类都是可以throwcatch的,那么如果在需要统⼀处理异常的地⽅,我们应该catch (Throwable th) 还是 catch

(Exception)呢?

这两种处理的区别在于,catch throwable会把Error和其他继承Throwable的类捕捉到。⽽catch Exception只会捕捉Exception极其⼦类,捕

捉的范围更⼩。先不考虑有其他的类继承了Throwable的情况下(附录A),第⼀种catch相当于⽐第⼆种catch多捕捉了把Error和其⼦类。

那么究竟Error是否需要捕捉呢?JDKError类的的注释(如下)⾥提到过,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.

Java Lanuage Spec 7 中也提到:Error继承⾃Throwable⽽不是继承⾃Exception,是为了⽅便程序可以使⽤ "catch (Exception)"来捕捉异常

⽽不会把Error也捕捉在内,因为Exception发⽣后可以进⾏⼀些恢复⼯作的,但是Error发⽣后⼀般是不可恢复的。

The class Error is a separate subclass ofThrowable, distinct from Exception in the class hierarchy, to allow programs to use the

idiom "} catch (Exception e) { " (§11.2.3) to catch all exceptions from which recovery may be possible without catching errors

from which recovery is typically not possible.

已经不难看出,Java本⾝设计思路就是希望⼤家catch Exception就⾜够了,如果有Error发⽣,catch了也不会有什么作⽤(附录B)。

引申,如何设计异常体系?

如何设计异常体系要根据你的项⽬的情况,类库框架,应⽤程序的异常设计⽅式都会有⼀些区别。下⾯简单谈谈个⼈对异常设计的⼀些看法

类库/框架

继承RuntimeException扩展⼀个新的异常作为整个类库的异常基类。这个异常应该可以满⾜⼤部分类库对异常的要求。

在实现中,在任何需要捕捉checked exception的地⽅都会把异常统⼀转化成这个新的异常。

对于有特殊需求,需要⾃定义异常的,就通过继承这个基类来实现⾃定义异常。

不对异常记录log(交给上层来处理)

案例

fastjson

spring ⾃定义异常⽐较多,不过都是继承⾃RuntimeException,⽽这个异常也是继承⾃

RuntimeException

应⽤程序

设计上和框架异常类似,只是在捕捉checked exception的时候需要log

如果需要根据异常进⾏不同的处理,建议给⾃定义异常增加⼀个ERROR_CODE字段,这样⽆论在服务器还是客户端都可以根据不同

ERROR_CODE进⾏对应的处理。但是出现这种情况的时候,应该需要考虑⼀下设计思路了,⼀般来讲根据异常来决定业务流程不

是⼀个好的设计⽅案。

附录A:是否应该直接继承Throwable来扩展新的异常?

个⼈认为异常都应该继承⾃Exception或者RuntimeException,⽽且Java本⾝对ExceptionError的规划就很清晰了,Java⾃⼰类库中没有

异常是直接继承⾃Throwable的。

附录BError可以catch吗? 可以catch了后做些其他处理吗?

Error是可以catch的,⽽且也可以向常规Exception⼀样被处理,⽽且就算不捕捉的话也只是导致当前线程挂掉,其他线程还是可以正常运

⾏,如果有需要的话捕捉Error之后也可以做些其他处理。但是Error是⼀种系统内部的错误,这种错误不像Exception⼀样是可能是程序和业

务上的错误是可以恢复的。

假设进⾏⽹络连接操作的时候,IOException 发⽣了,可能是⽹络中断,我可以再尝试⼏次。

假设OutOfMemoryError发⽣了,就算被捕捉了,可以有什么⼿段让程序正常运⾏下去吗? 假设ExceptionInInitializerError发⽣了,类⽆法被

正常初始化,这个是可以通过捕捉来恢复的吗?