什么时候InvocationTargetException.getCause()null?

根据javadocs , InvocationTargetException.getCause()可以为null:

返回此exception的原因(抛出的目标exception,可能为null)。

但文档还说它包装了一个现有的exception:

InvocationTargetException是一个已检查的exception,它包装被调用的方法或构造函数抛出的exception。

所以在我看来, InvocationTargetException.getCause() 永远不能为null

我错过了什么吗?

UPDATE

是的,我错过了一些东西 – InvocationTargetException的默认构造函数会导致getCause()为null。

我现在的问题是为什么要提供这个类的默认构造函数。 是否存在需要使用null原因抛出exception的用例?

InvocationTargetException扩展了InvocationTargetException ReflectiveOperationException

核心reflection中reflection操作抛出的常见超类exception。

使用reflection调用方法(或构造函数)时。

 Method method = ... method.invoke(instance, ...); 

如果方法抛出exception,它将存储在InvocationTargetExceptiontarget字段中。 在大多数反思案例中都会发生这种情况。

有一个空构造函数的事实让我相信它可能在其他情况下使用不同。

JDK 7

 private Throwable target; /** * Constructs an {@code InvocationTargetException} with * {@code null} as the target exception. */ protected InvocationTargetException() { super((Throwable)null); // Disallow initCause } 

所以。

@ xtravar对我(很多)早期答案的评论导致我们再看看这个问题。 我可能刚刚得到它。 请多多包涵。

InvocationTargetException很早就被引入了Java。 至少早在1997年2月到1998年12月之间的一些JDK 1.1.X。 我怎么知道那是旧的? 毕竟, @since 1.1上没有@since 1.1分。
我碰巧在serialVersionUID字段上看到以下javadoc:

 /** * Use serialVersionUID from JDK 1.1.X for interoperability */ 

对。 所以呢?
因此,根据Throwable.getCause()文档, InvocationTargetException最终会inheritance:

 While it is typically unnecessary to override this method, a subclass can override it to return a cause set by some other means. This is appropriate for a "legacy chained throwable" that predates the addition of chained exceptions to Throwable. ... @since 1.4 

现在,请将此与InvocationTargetException类docs的以下注释结合起来:

 As of release 1.4, this exception has been retrofitted to conform to the general purpose exception-chaining mechanism. The "target exception" that is provided at construction time and accessed via the getTargetException() method is now known as the cause, and may be accessed via the Throwable.getCause() method, as well as the aforementioned "legacy method." 

看看我在哪里?
关于Throwable.getCause()的注释完全针对InvocationTargetException (为最少)。 在将exception链引入Throwable 之前, InvocationTargetExcpetion用于链接exception…

如上所述,当InvocationTargetException被改装时,我认为语言设计者想要:

  1. 防止InvocationTargetException有两个不同的“原因” – 一个存储在target ,另一个存储在cause ; 还是
  2. 与依赖于target字段的现有代码向后兼容。

这就是为什么他们将target字段保留为真正使用并实现任何现有构造函数的target字段,以便cause字段保持为null 。 当然, InvocationTargetExceptiongetCause()实现会返回target作为原因。

所以回答

是否存在需要使用null原因抛出exception的用例?

不是真的,并不是这个课程的用途 – 而且是 – 有意使用。

然而,这个问题仍然存在:

为什么要提供这个类的默认构造函数

( 此后这个构造函数似乎存在 )

我倾向于认为这个类实际上是非常容忍的。 毕竟, public构造函数允许null作为Throwable target 。 作为设计者,如果您已经允许,那么您也可以添加显式为target指定nullprotected默认构造函数,从而允许inheritance类来构造所需的类。

这也回答了原来的问题:

所以在我看来,InvocationTargetException.getCause()永远不能为null。

我错过了什么吗?

是。 InvocationTargetException确实旨在具有非null targetcause 。 然而,这里“遗漏”的是,遗憾的是, target (以及因此cause可以null ,因为类中的任何东西都不会强制它。

我同意你的观点 – 我不知道InvocationTargetException如何可以为null,因为它仅在目标抛出exception时抛出。

我的猜测是getCause()的文本声明“可能为null”只是从Throwable.getCause()Javadoc复制的样板文件。

首先,值得一提的是,通过protected构造函数不仅允许null原因。 您还可以调用target值为nullpublic构造函数。 不会发生NullPointerException

话虽如此,它确实看起来不仅仅是设计师刚刚滑倒的东西。

可能是设计者想要通过reflection实现类的实例化,如:

 Constructor ctor = // ... some code to get the no-arg constructor that I spared here ctor.setAccessible(true); // it's protected constructor... InvocationTargetException e = (InvocationTargetException) ctor.newInstance(); 

这样,util方法可以创建InvocationTargetException实例并将它们传递给客户端代码,从而将特定原因相加。