是否有任何理由将异常的原因设置为自身?

2022-09-02 23:19:17

我在Java库中遇到过一些我正在构建的地方,其中异常的原因被设置为异常本身。

是否有任何理由将例外本身作为其原因?

编辑

根据要求,这里有一个具体的例子:

enter image description here


答案 1

我经常看到框架或库(如Hibernate或Spring引用)引发的异常本身就是原因(在此过程中混淆了调试器GUI)。

我一直想知道他们为什么这样做,因为这似乎是一个坏主意。今天,当我试图将一个序列化为JSON时,它实际上引起了一个问题:bam,无周期。

所以我进一步研究了它:

在源代码中(这里列出的所有源代码都来自JDK 1.7),我们有这个:Throwable

 /**
     * The throwable that caused this throwable to get thrown, or null if this
     * throwable was not caused by another throwable, or if the causative
     * throwable is unknown.  If this field is equal to this throwable itself,
     * it indicates that the cause of this throwable has not yet been
     * initialized.
     *
     * @serial
     * @since 1.4
     */
    private Throwable cause = this;

现在我特别遇到了一个扩展的异常类的问题,所以我从那里开始。的构造函数之一:RuntimeExceptionRuntimeException

/** Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     *
     * @param   message   the detail message. The detail message is saved for
     *          later retrieval by the {@link #getMessage()} method.
     */
    public RuntimeException(String message) {
        super(message);
    }

由上述调用的 构造函数:Exception

 /**
     * Constructs a new exception with the specified detail message.  The
     * cause is not initialized, and may subsequently be initialized by
     * a call to {@link #initCause}.
     *
     * @param   message   the detail message. The detail message is saved for
     *          later retrieval by the {@link #getMessage()} method.
     */
    public Exception(String message) {
        super(message);
    }

由上述调用的 构造函数:Throwable

/**
     * Constructs a new throwable with the specified detail message.  The
     * cause is not initialized, and may subsequently be initialized by
     * a call to {@link #initCause}.
     *
     * <p>The {@link #fillInStackTrace()} method is called to initialize
     * the stack trace data in the newly created throwable.
     *
     * @param   message   the detail message. The detail message is saved for
     *          later retrieval by the {@link #getMessage()} method.
     */
public Throwable(String message) {
    fillInStackTrace();
    detailMessage = message;
}

fillInStackTrace是一种本机方法,并且似乎不会修改原因字段。

因此,如您所见,除非随后调用该方法,否则该字段永远不会从 的原始值更改。initCausecausethis

结论 :如果您使用不带参数的构造函数创建一个新的(或存在于野外并且不覆盖此行为的许多子类之一),并且您不调用该方法,则异常的原因将是它本身!ExceptioncauseinitCause

所以我想这应该使它成为一个非常普遍的情况。


答案 2

接受的答案具有误导性,其他答案是不完整的。所以。。。

虽然将异常作为其自身原因传递糟糕的设计,但正是由于这个原因,在Shrewable实现中是不可能的。原因要么在构造过程中传递,要么传递到initCause()方法,并且如第二个答案中指出的那样,后者将导致非法参数异常。

正如第三个答案所指出的那样,如果你没有提供原因,那么根据Srowtable实现,原因将是这个

可能缺少的(给定原始问题)是Spredable的getCause()方法永远不会返回这个,如果原因==this,它将返回null。因此,尽管调试器将此引用显示为原因,因为它正在使用反射,但在使用 Throwable 的公共接口时,您将看不到它,因此它不会成为问题。