//这次博客是对我所写的java异常处理1(基本技术)的一个补充,如果对java的异常处理机制还未理解请移步https://www.jianshu.com/p/4287c5220c0e阅读。
异常的链化
在一些大型的,模块化的软件开发中,一旦一个地方发生异常,则如骨牌效应一样,将导致一连串的异常。假设B模块完成自己的逻辑需要调用A模块的方法,如果A模块发生异常,则B也将不能完成而发生异常,但是B在抛出异常时,会将A的异常信息掩盖掉,这将使得异常的根源信息丢失。异常的链化可以将多个模块的异常串联起来,使得异常信息不会丢失。
异常链化:以一个异常对象为参数构造新的异常对象。新的异对象将包含先前异常的信息。这项技术主要是异常类的一个带Throwable参数的函数来实现的。这个当做参数的异常,我们叫他根源异常(cause)。
查看Throwable类源码,可以发现里面有一个Throwable字段cause,就是它保存了构造时传递的根源异常参数。这种设计和链表的结点类设计如出一辙,因此形成链也是自然的了。
Throwable源码 一个加法器的示例 运行结果自定义异常
如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException。
按照国际惯例,自定义的异常应该总是包含如下的构造函数:
1.一个无参构造函数
2.一个带有String参数的构造函数,并传递给父类的构造函数。
3.一个带有String参数和Throwable参数,并都传递给父类构造函数
4.一个带有Throwable 参数的构造函数,并传递给父类的构造函数。
下面是IOException类的完整源代码,可以借鉴。
IOException类的完整源代码异常的注意事项
1、当子类重写父类的带有 throws声明的函数时,其throws声明的异常必须在父类异常的可控范围内——用于处理父类的throws方法的异常处理器,必须也适用于子类的这个带throws方法 。这是为了支持多态。
例如,父类方法throws 的是2个异常,子类就不能throws 3个及以上的异常。父类throws IOException,子类就必须throws IOException或者IOException的子类。
2、Java程序可以是多线程的。每一个线程都是一个独立的执行流,独立的函数调用栈。如果程序只有一个线程,那么没有被任何代码处理的异常 会导致程序终止。如果是多线程的,那么没有被任何代码处理的异常仅仅会导致异常所在的线程结束。
也就是说,Java中的异常是线程独立的,线程的问题应该由线程自己来解决,而不要委托到外部,也不会直接影响到其它线程的执行。
finally块和return
示例代码 运行结果try-catch中的finally会永远执行,就算try中方法体有返回值并正常终结。
但是在异常中还是会有让人想不到的情况发生:
1、finally中的return 会覆盖 try 或者catch中的返回值。
2、finally中的return会抑制(消灭)前面try或者catch块中的异常
3、finally中的异常会覆盖(消灭)前面try或者catch中的异常
为了避免这些情况,因为这些情况出现了会让人很迷惑。在此有几条忠告:
1、 不要在fianlly中使用return。
2、不要在finally中抛出异常。
3、减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。
4、将尽量将所有的return写在函数的最后面,而不是try … catch … finally中。
网友评论