Java 中的Exception 有什么用?

Exception 的作用,这个问题是一个开放性的问题,没有标准的答案,不同经历的人可能会有不同的答案,也就是说经历过惨痛的经历后,才会对Java Exception 有深刻的认识,单纯理论学习,按部就班的按所谓的规范使用,无法准确的表达出Java Exception 的内在逻辑。

Exception 含义

Exception,顾名思义,代表着程序运行的过程中出现一种不正常的状态,需要中止程序的持续运行,同时又能快速的发现程序为什么会出现错,通过异常的信息能够快速定位,所以异常需要提供错误的上下文的状态信息,尤其是应用系统自身抛出的异常,需要将上下文状态尽可能多的输出,有助于排查和定位。Java 中的NullPointerException 对外提供的信息极少,所以应用系统应该尽可能catch 这类异常,包装为信息量更加丰富的异常抛出。

Exception 也是一种程序逻辑控制的方式,是程序健壮性的一种表现。其实,大都数异常,程序都应该有一定的相应的处理逻辑,例如,ArrayIndexOutOfBoundsException,这类异常在编码过程中应该能够被预见,并需要做出现相应的逻辑控制,有经验的程序员,在编码的过程中就已经考虑到各种异常的情况,待整个系统上线后,出现的问题相对较少,而普通的程序员往往只保证程序在Happy Case 时能够正常运行,却忽略了各种异常情况,往往是在出现问题后进行补救,导致程序在反复补救后,逻辑混乱,这也就是很多项目早期的代码质量高,经过一段时间后,代码惨不忍睹的根源。

Exception 的处理方式

什么时候需要catch Exception?什么时候需要throw 呢?这也是不会有标准答案的过程,Java 本身也没有给出标准答案,也没有指导原则。但经过无数次实践的经验后,你就能体会对异常的不同处理方式,对系统逻辑的稳定性性有着截然不同的影响,往往出现很诡异的Bug时,同时可参考的日志或其它关键丢失,导致故障不能及时解决,才会发现关键的位置异常被人为的隐藏是多么愚蠢的行为。

我在使用一个开源的框架时,时常会发现重要的异常信息被隐藏,导致花费大量的时间去跟踪代码。异常在什么时候需要throw,什么时候需要catch,原则其实很简单:

  1. 异常在能够完全掌控的情况下,而且也有明确的逻辑处理时,需要catch,并进行相应的处理。同时,也需要关注外部程序是否需要感知异常,如果需要,则封装新的异常后重新throw;
  2. 无法决定处理逻辑的情况下,需要将所有异常throw,让外部程序决定处理逻辑。同时,针对内部的信息含量较少的Runtime 型的异常,需要额外封装,避免在同一行代码中,无法确定哪一个对象为null。

Exception 定义

什么时候定义Exception 同样是没有任何指导原则,不同的技术框架中对异常定义的方式和方法都不太一样,毕竟每个应用系统的逻辑结构和复杂度都不太一定,我根据自身的经验整理了两个指导原则:

  1. 程序需要中止,自身又无法完整的处理逻辑转折,只能由外部调用者根据异常的信息,作为合理的逻辑处理,例如:数据采集时,出现了非法的数据或字符串,采集程序是无法判断逻辑转折后,就如何处理,同时又需要明确区分非常数据,甚至需要定义出错误的类型,由外部程序决定是忽略还是终止执行,在这种情况下需要定义明确的异常,用于标识错误的类型。
  2. 内部程序处理过程中出现太多异常,并且这类异常具有共同的特性(例如:ClassNotFountException, NoSuchMehtodException 等),不需要外部程序对这类异常分别处理时,需要定义一个异常用于包装内部异常,提升代码的可读性。
  3. 错误信息的补充,例如上文所提到的NullPointerException,应用系统程序需要为此异常补充更完整的信息,便于外部程序或日志系统提供足够的信息,便于故障的解决;

Exception 和 RuntimeException 有什么区别,在什么场景下定义,也是一个仁者见仁,智者见智的问题,Java 没有任何指导建议,按我个人的判断,JDK中也有很多的定义也不是特别合理,例如:IndexOutOfBoundsException 应该是一个Exception, JDK 却定义为RuntimeExcption 这类错误需要明确的提醒外部程序对数组进行逻辑限制,很多应用系统在总是在出现错误后,才能主动Cache 这类异常;然而像 ClassNotFoundException 这类异常在极少数状态下才会进行逻辑处理JDK 却定义为Exception 导致很多反射类的项目的处理逻辑变得复杂,NullPointerException 也是经常出现的,但定义为RuntimeException 是合理的,可能因为JDK 程序从逻辑上根本无法捕捉NullPointerException,应该是在JVM 执行过程中才能够进行逻辑判断,具体并未研究。

经过上面的两个示例也很容易看出Exception 和RuntimeException 有什么区别,JDK 的设计应该从外部程序使用的角度进行异常设计,由于外部程序导致的异常,并且外部程序应当有逻辑处理异常状态,这类异常理应定义为Exception,而其它由于JVM 在编码期无法判断,也无法从语法层面提供解释的Exception 应该定义为RuntimeException。

结论

针对Java 异常的解读是我个人的见解,就像古诗词一样,不同人有不同的解读,相信JDK 的设计者也无法给 Java Exception 一个明确的解释和原则,只能靠历史经验的积累和不断的错误中,逐形成相对完整的理论,供后人学习。

本作品采用《CC 协议》,转载必须注明作者和本文链接
ObjectiveSql
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
leader @ ObjectiveSql
文章
1
粉丝
0
喜欢
0
收藏
0
排名:3444
访问:51
私信
所有博文
社区赞助商