先来看一下API中对cause的解释:
Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。最后,它还可以包含 cause(原因):另一个导致此 throwable 抛出的 throwable。此 cause 设施在 1.4 版本中首次出现。它也称为异常链 设施,因为 cause 自身也会有 cause,依此类推,就形成了异常链,每个异常都是由另一个异常引起的。
导致 throwable cause 的一个理由是,抛出它的类构建在低层抽象之中,而高层操作由于低层操作的失败而失败。让低层抛出的 throwable 向外传播是一种糟糕的设计方法,因为它通常与高层提供的抽象不相关。此外,这样做将高层 API 与其实现细节关联起来,假定低层异常是经过检查的异常。抛出“经过包装的异常”(即包含 cause 的异常)允许高层与其调用方交流失败详细信息,而不会招致上述任何一个缺点。这种方式保留了改变高层实现而不改变其 API 的灵活性(尤其是,异常集合通过其方法抛出)。
导致 throwable cause 的另一个 cause 是,抛出它的方法必须符合通用接口,而通用接口不允许方法直接抛出 cause。例如,假定持久集合符合 Collection 接口,而其持久性在 java.io 的基础上实现。假定 add 方法的内部可以抛出 IOException。实现可以与其调用方交流 IOException 的详细消息,同时通过以一种合适的未检查的异常来包装 IOException,使其符合 Collection 接口。(持久集合的规范应该指示它能够抛出这种异常。)
可以说很直观的解释了,但是具体怎么体现cause还有点模糊,于是手动测试:
public class LowerLevel { public void throwException(){ throw new RuntimeException("lower exception"); }}
public class HighLevel { LowerLevel ll = new LowerLevel(); public void hi(){ try{ ll.throwException(); }catch (Exception e){ throw new RuntimeException("high",e); } } public static void main(String[] args) { HighLevel highLevel = new HighLevel(); highLevel.hi(); }}
执行之后抛出异常,控制台中打印的异常栈如下:
Exception in thread "main" java.lang.RuntimeException: high at com.iqiyi.mams.web.listener.HighLevel.hi(HighLevel.java:12) at com.iqiyi.mams.web.listener.HighLevel.main(HighLevel.java:18) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)Caused by: java.lang.RuntimeException: lower exception at com.iqiyi.mams.web.listener.LowerLevel.throwException(LowerLevel.java:9) at com.iqiyi.mams.web.listener.HighLevel.hi(HighLevel.java:10) ... 6 more
吼吼吼,一看就明白。同时还明白了异常中出现的6more是什么意思,数了一下,在上面hi下面的异常栈数量=6。以前还疑惑这个more到底去了哪里。