Есть ли какая-либо причина устанавливать для себя причину исключения? - PullRequest
10 голосов
/ 10 февраля 2012

Я сталкивался с некоторыми местами в библиотеках Java, против которых я создаю, где причиной исключения является само исключение.

Есть ли причина, по которой исключение может ссылаться на себя как на причину?

EDIT

По запросу, вот конкретный пример:

enter image description here

Ответы [ 4 ]

14 голосов
/ 16 апреля 2014

Я часто видел исключения, генерируемые инфраструктурами или библиотеками, такими как Hibernate или Spring, ссылающиеся на себя как на причину (путая графический интерфейс отладчика в процессе).

Я всегда удивлялся, почему они это сделали, так как кажетсятакая плохая идея.И сегодня это на самом деле вызвало проблему, когда я пытался сериализовать один в 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;

Теперь я специально столкнулся с проблемой с классом исключений, который расширил 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);
    }

Конструктор 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 является нативным методом и, похоже, не изменяет поле причины.

Итак, как вы можете видеть, если только метод initCause не вызывается впоследствии, causeполе никогда не изменяется от исходного значения this.

Вывод: если вы создаете новый Exception (или один из множества подклассов, которые существуют в wild и не переопределяют это поведение)используя конструктор, который не принимает аргумент cause, и вы не вызываете метод initCause, причиной исключения будет сама!

Так что я думаю, это должно сделать его оченьобычное явление.

10 голосов
/ 24 июня 2016

Принятый ответ вводит в заблуждение, а остальные ответы являются неполными. Итак ...

Хотя было бы плохим дизайном, чтобы передавать исключение как собственную причину, в реализации Throwable по этой причине это невозможно. Причина либо передается во время построения, либо в метод initCause (), и, как указано во втором ответе, последний может привести к исключению IllegalArgumentException.

Как показывает третий ответ, если вы не предоставите причину, причина будет this согласно реализации Throwable.

Что может отсутствовать (учитывая исходный вопрос), так это то, что метод getCause () Throwable никогда не возвращает this , он возвращает ноль, если причина == this. Поэтому, хотя ваш отладчик показывает ссылку this в качестве причины, поскольку он использует отражение, при использовании открытого интерфейса Throwable вы его не увидите, и поэтому это не будет проблемой.

3 голосов
/ 10 февраля 2012

Из источников Throwable У меня есть здесь:

public synchronized Throwable initCause(Throwable cause) {
    ...
    if (cause == this)
        throw new IllegalArgumentException("Self-causation not permitted");
    ...
}

Я не вижу, как вообще возможно установить причину для себя.

2 голосов
/ 10 февраля 2012

Нет, это просто плохой дизайн. Если исключение является основной причиной, ему не нужно определять причину.

Исключение, имеющее причину, является допустимым случаем для различных упаковок исключений. Например, если вы создаете хранилище, вы можете захотеть выбросить PersistenceExcpetion. Итак, если это хранилище файлов, вы можете иметь причину IOException. Если это база данных, возможно, причина в SqlException. Etc

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...