有没有理由为自己设置例外原因?

aro*_*eer 12 java exception

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

是否有任何理由将异常引用为其原因?

编辑

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

在此输入图像描述

Pie*_*nry 15

我经常看到框架或库引发的异常,例如Hibernate或Spring引用本身作为原因(在过程中混淆了调试器GUI).

我总是想知道为什么他们这样做,因为它似乎是个坏主意.今天,当我尝试将一个序列化为JSON时,它实际上引起了一个问题:bam,enless cycle.

所以我进一步调查了一下:

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

 /**
     * 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;
Run Code Online (Sandbox Code Playgroud)

现在我特意遇到了一个扩展的异常类的问题RuntimeException,所以我从那里开始.其中一个构造函数RuntimeException:

/** 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);
    }
Run Code Online (Sandbox Code Playgroud)

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);
    }
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

fillInStackTrace 是一个本机方法,似乎没有修改原因字段.

正如您所看到的,除非initCause随后调用该方法,否则该cause字段永远不会从原始值更改this.

结论:如果您Exception使用不带cause参数的构造函数创建一个新的(或者在野外存在的许多子类中的一个并且不覆盖此行为),并且您不调用该initCause方法,那么原因是例外将是它自己!

所以我想这应该是一个非常常见的事情.

  • 你确实可以创建一个自我引发的异常,只做`Exception ex = new RuntimeException("ex");`但是`ex.equals(ex.getCause())`仍会返回`false`,因为`Throwable`实现:`return this.cause == this?null:this.cause;` (4认同)

小智 11

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

虽然异常作为其自身原因传递是不好的设计,但在Throwable实现中出于这个原因是不可能的.原因是在构造期间传入,或者传递给initCause()方法,并且如第二个答案所指出的,后者将导致IllegalArgumentException.

作为第三个答案指出,如果你不提供一个原因,原因将是这个按照该实施的Throwable.

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


Mic*_*ael 1

不,那只是糟糕的设计。如果异常是根本原因,则不需要定义原因。

有原因的异常是不同异常包装的合法情况。例如,如果创建持久性存储,您可能想要抛出 PersistenceExcpetion。因此,如果它是文件存储,则原因可能是 IOException。如果是数据库,可能原因是 SqlException。ETC