为了账号安全,请及时绑定邮箱和手机立即绑定

Throwable.initCause() 并通过构造函数设置原因:为什么我们只能设置一次原因?

Throwable.initCause() 并通过构造函数设置原因:为什么我们只能设置一次原因?

慕工程0101907 2021-06-10 13:01:50
为什么我们Throwable.initCause()只能在Throwable/Exception对象上调用一次?为什么如果原因异常是由构造函数设置的,那么我们不能使用 再次设置它initCause()吗?我们可以为异常设置多个原因吗?
查看完整描述

2 回答

?
阿晨1998

TA贡献2037条经验 获得超6个赞

为什么我们只能在 Throwable/Exception 对象上调用 Throwable.initCause() 一次?为什么如果原因异常是由构造函数设置的,那么我们不能使用 initCause() 再次设置它吗?


Throwable.initCause() 允许我们使用不设置原因异常的构造函数实例化异常,并在第二次设置异常原因:


MyException e = new MyException();

e.initCause(rootException);

或者 :


MyException e = new MyException("error message...");

e.initCause(rootException);

因此,您必须将其视为接受原因异常作为参数的 arg 构造函数的替代方案:


MyException e = new MyException(rootException);

您可以一次设置原因异常,因为它不是为修改而设计的:如果为某个原因抛出异常,则该原因不会改变。

因此,为客户端类提供这种可能性可能容易出错。

但是语言设计者也允许设置原因异常,即使我们要实例化的异常类没有提供接受原因异常作为参数的构造函数。于是他们介绍initCause()。

但在大多数情况下,您不想使用这种方法。调用传递异常原因的 arg 构造函数更简单、更直接。


我们可以为异常设置多个原因吗?


不,这是不可能的:由于单个直接异常可能会发生 n 异常。

但是异常可能是由多个中介/先前抛出的异常引起的。

因此,您可以将异常链接到 2 之外,如前面的示例所示:


MyException e = new MyException(rootException);

例如假设a()调用b(),c()如果发生错误,每个方法可能会抛出异常:


void a(){  

    try{

        b();

    }

    catch(SecondException e){

       throw new ThirdException(e);

    }    

}


void b(){        

    try{

        c();

    }

    catch(FirstException e){

       throw new SecondException(e);

    }

}


void c(){

     throw new FirstException();

}

如果所有这些方法都抛出自己的异常,你在最后的堆栈跟踪3种链式异常ThirdException: ThirdException引起SecondException引起FirstException。

就像你写过:


new ThirdException(new SecondException(new FirstException()));

但作为奖励,每个创建的异常的线程执行堆栈的快照。


查看完整回答
反对 回复 2021-06-17
?
aluckdog

TA贡献1847条经验 获得超7个赞

这纯粹是一种设计选择。我不知道 Sun/Oracle 的原作者,但异常的整体设计似乎是它们应该被视为不可变对象。如果您考虑一下,这实际上是有道理的 - 如果异常在创建后可以更改,那肯定会使任何调试成为一场噩梦!


查看完整回答
反对 回复 2021-06-17
  • 2 回答
  • 0 关注
  • 164 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信