1 - 异常前后,各相关部分的状态
某个异常何时发生?
因为什么发生?
一旦异常发生,各相关的对象(数据)都将处于何种状态?(所谓相关对象,就是说方法调用路径所经过的每一层的对象,从 new 异常的那一层一直到 catch 异常的那一层)
或者你无法预料这些对象、数据将会处于什么状态?
程序还能不能继续运行?
如果相关对象、数据在异常发生后都处于可以预料的稳定状态并且程序能继续运行,要不要提示信息给用户?
提示什么信息给用户?
异常有没有可能是用户操作错误导致的?
用户有没有办法通过更正操作等方式调用同一个功能,成功避免这个异常?
如果异常不是用户操作导致的,那么程序继续运行,用户做同样的操作,会不会总是发生这个异常?
=====
-> 如果异常发生后,你不能预料相关对象或数据的状态,或者你预料相关的对象或数据将会处于一种不稳定(或非法)的状态,比如对象内部的状态不再遵从其应有的约束(constraints),如果对对象进行进一步的操作,将会导致不可预料的行为………… 那么这种异常不可恢复,属于应该导致程序崩溃退出的异常。这时,显示友好的信息给用户,比如 “为了防止(对数据产生)更多的损害,程序将停止运行………………”,然后尽最大努力安全结束程序。
这样的异常,应该设计成非检查异常(unchecked exception),一般即 extends RuntimeException 或其子类型。
-> 如果异常是因为非法的用户输入导致的,那么应该在程序中避免,即非法的用户输入应该在其导致异常之前就检验出其不合法,然后不去调用功能,而是反馈合适的信息给用户。
如果检查输入的合法性代价非常昂贵,或者在调用功能之前无法检查其合法性:一种可能是这个功能的设计有问题;如果没有问题,就是无法在调用功能之前检查,或者检查太昂贵,那么就只能 try - catch,这时要明确一旦异常发生,整个调用路径的每一层都将出于什么状态,如果要确保异常发生之后程序能继续运行,那么每一层都应该处于原本调用之前的状态,就像调用没有发生一样。然后你就可以放心给用户提示信息,然后让用户重试了。
(在调用功能之前无法检查其合法性,这种情况大概多存在于多线程环境下,当某接口对外保证线程安全的时候)
这里的异常,可以设计成检查异常(checked exception),也可以设计成非检查异常。这是设计上的取舍问题,如果调用路径很长而你不愿意污染每一层方法的签名(throws),——那么设计成非检查异常。这里的核心问题是注明异常发生后的状态。
这里需要补充一句细节,多线程环境下,对于某后台线程发生的,而这个线程本身又不能处理的,应该导致程序崩溃退出的异常,使用 Thread.UncaughtExceptionHandler,具体用法可以查API文档。
|