9

根据javadocsInvocationTargetException.getCause()可以为空:

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

但是文档还说它包装了一个现有的异常:

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

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

我错过了什么吗?

更新

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

我现在的问题是为什么要为这个类提供一个默认构造函数。是否存在需要以空原因引发异常的用例?

4

4 回答 4

2

所以。

@xtravar 对我(很多)较早的答案的评论导致重新审视这个问题。我可能刚刚得到它。请多多包涵。

InvocationTargetException很早就被引入Java。至少可以追溯到1997 年 2 月到 1998 年 12 月之间的任何 JDK 1.1.X。我怎么知道它这么旧?毕竟,@since 1.1课堂上没有分数。
我碰巧在serialVersionUID现场看到以下 javadoc:

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

正确的。所以呢?
因此,根据 docs of Throwable.getCause(),它InvocationTargetException最终继承了:

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类文档中的以下注释结合起来:

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(至少)。在将异常链接引入...之前InvocationTargetExcpetion用于链接异常Throwable

如前所述,当InvocationTargetException进行改造时,我假设语言设计者想要:

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

这就是为什么他们将这个target领域作为真正使用并实现了任何现有构造函数的领域,以便该cause领域永远存在null。当然,getCause()for的实现作为原因返回。InvocationTargetExceptiontarget

所以来回答

是否存在需要以空原因引发异常的用例?

并非如此,这不是该类的用途——而且是——打算使用的方式。

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

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

(并且这个构造函数似乎从那以后就存在了

我倾向于认为这个类实际上是相当null宽容的。毕竟,public构造函数允许null作为Throwable target. 作为设计者,如果您已经允许这样做,您也可以添加显式分配给的protected默认构造函数,从而使继承类能够根据需要构造类。nulltarget

这也回答了原来的问题:

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

我错过了什么吗?

是的。InvocationTargetException确实打算有一个非null targetcause。然而,这里“遗漏”的是target(因此cause)不幸的是可以null,因为课堂上没有任何东西强迫它。

于 2017-01-28T22:46:41.013 回答
1

InvocationTargetException扩展ReflectiveOperationException哪些状态

核心反射中反射操作抛出的常见异常超类。

当您使用反射调用方法(或构造函数)时。

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

如果方法抛出异常,它将存储targetInvocationTargetException. 在大多数反射情况下都会发生这种情况。

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

JDK 7

private Throwable target;

/**
 * Constructs an {@code InvocationTargetException} with
 * {@code null} as the target exception.
 */
protected InvocationTargetException() {
    super((Throwable)null);  // Disallow initCause
}
于 2013-07-16T18:47:35.787 回答
0

首先,值得一提的是,构造函数不仅null允许原因。protected您还可以调用带有to 值的public构造函数。不会发生...targetnullNullPointerException

话虽如此,它似乎不仅仅是设计师刚刚滑倒的东西。

可能是设计人员希望通过反射来实例化类,如下所示:

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实例并将它们传递给添加特定原因的客户端代码。

于 2013-07-16T19:57:05.797 回答
0

我同意你的看法——我看不出 InvocationTargetException 怎么可能是空的,因为它只有在目标抛出异常时才会被抛出。

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

于 2013-07-16T18:50:03.430 回答