Подтвердить что ты не робот

Выброс связанного списка исключений в Java

У меня есть функция, которая петляет, делая что-то, что может вызвать исключение. Выглядит примерно так:

public void myFunction() throws MyException {
    while(stuff) {
        try {
            DoSomething() // throws an exception
        }
        catch (Exception ex) {
            throw new MyException(some, stuff, of, mine, ex);
        }
    }
}

Ошибка, вызывающая исключение, восстанавливается. Это может быть что-то вроде ошибки SQL в одном операторе обновления, где цикл while выполняет серию операторов обновления. Или ошибка синтаксического анализа в одном фрагменте данных, где цикл обрабатывает несколько фрагментов данных. Мне нужно передать исключение дальше по цепочке, так что часть GUI программы может обрабатывать ее, обрабатывать и передавать ошибку пользователю. Но я не хочу убивать цикл в этой конкретной функции. Другие вещи, которые он делает, могут быть недействительными. Ошибка, вызвавшая это исключение, может не оказаться фатальной для функции.

Итак, мой вопрос таков: Является ли приемлемой практикой создание связанных списков пользовательских исключений (где каждое исключение - node, а исключение - глава списка), а затем бросать голову списка (если есть) после завершения цикла?

Кто-нибудь когда-либо видел это? Может ли кто-нибудь думать о каких-либо потенциальных проблемах с этим? Может ли кто-нибудь подумать о других, более эффективных способах устранения проблемы с корнем: необходимо ли передавать несколько несвязанных исключений без выхода из функции до тех пор, пока она не будет выполнена?

Вот пример того, как ссылка и бросок могут быть реализованы очень просто:

public void myFunction() throws MyException {
    MyException head = null;
    while(stuff) {
        try {
            DoSomething() // throws an exception
        }
        catch (Exception ex) {
            MyException tmp = new MyException(some, stuff, of, mine, ex);
            tmp.next(head);
            head = tmp;
        }
    }
    if(head != null)
       throw head;
}
4b9b3361

Ответ 1

Моя внутренняя мысль (за исключением того, что я этого не видел) заключается в том, что исключение - потенциально довольно большой объект (содержащий стек), и я бы предпочел не хранить их много.

Вместо этого я бы создал список ошибочных параметров/аргументов по мере возникновения исключений и по завершении цикла выбросил настраиваемое исключение, заполненное этим списком (если список содержит более 0 элементов). Это выглядит более управляемым способом обработки этого сценария.

public void myFunction() throws CustomException {
    List<MyError> errors = new ArrayList<MyError>();
    while(stuff) {
        try {
            DoSomething() // throws an exception
        }
        catch (Exception ex) {
            errors.add(new MyError(some, stuff, of, mine, ex));
        }
    }
    if (errors.size() > 0) {
       throw new CustomException(errors);
    }
}

Ответ 2

Вам действительно нужно бросить все исключения? Как вы ожидаете, чтобы отдельные, не связанные с ними исключения были обработаны? Как правило, в таких случаях система будет просто сообщать об ошибках и делать с ними.

Если это так, вы можете просто собрать сообщения об ошибках и добавить их в пользовательский класс Exception и выбросить его.

Ответ 3

Если эти исключения действительно не связаны друг с другом, поэтому вы не можете воспользоваться get/setCause(), тогда я предпочел бы собирать эту информацию в одном MyException.

например.

public void myFunction() throws MyException {
    MyException myException = null;
    while(stuff) {
        try {
            DoSomething() // throws an exception
        }
        catch (Exception ex) {
            if (myException == null) {
                myException = new MyException();
            }
            myException.addException(some, stuff, of, mine, ex);
        }
    }
    if (myException != null) {
        throw myException;
    }
}

Обновление: Брайан обрабатывает именно этот подход более аккуратным образом. Я бы выбрал это вместо:)

Ответ 4

Фактически бросание любых исключений из такой функции, вероятно, не является правильным способом справиться с этим, если ожидается, что будут ошибки. Я предлагаю либо вернуть список (массив) всех исключений/ошибок, которые возникли или лучше предоставить объект обработчика ошибок функции, которая может иметь дело с исключениями. то есть:.

public interface ErrorHandler
{
    public void handleError( Throwable ex /*, add some context info */ );
}

public void myFunction( ErrorHandler eh )
{   
    while(stuff) {   
        try {   
            DoSomething() // throws an exception   
        }   
        catch (Exception ex) {
            if( eh != null )
                eh.handleError( ex );
        }   
    }   
}   

Это также позволяет обработчику ошибок собирать ошибки, чтобы представить их пользователю, или решить, что вся пакетная операция стала недействительной из-за некоторой ошибки и выбросить исключение из нее, чтобы прервать обработку раньше.

Ответ 5

Если исключение, созданное DoSomething();, может привести к тому, что тот же самый метод будет выдавать другое исключение; это может быть проблемой. Другими словами, если DoSomething(); выдает исключение, потому что вы не обрабатывали предыдущий, может возникнуть ошибка noecesarry для обработки.

Ответ 6

Я думаю, что вы можете передать какой-либо callback или прослушиватель в метод или установить в переменной класса, а не бросать список, например x4u.

В Java для этого уже есть интерфейс: java.beans.ExceptionListener

Ответ 7

IMO, исключение должно быть последним ресурсом, который вы имеете для обработки ошибки. Его следует избегать, если это возможно. Таким образом, вы можете передать описание ошибки (создать коды ошибок, передать сообщение или что-то значимое) в GUI, а не само исключение.