Java - разница между генерацией исключения и перехватом исключения - PullRequest
5 голосов
/ 08 марта 2012

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

Например

private void testMethod() throws Exception
{
    //some bad code here
} 

против

private void testMethod() throws Exception
{
    try
    {
        //some bad code here
    }
    catch (Exception e)
    {
        throw e;
    }
} //end testMethod()

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

Спасибо за помощь.

Ответы [ 7 ]

6 голосов
/ 08 марта 2012

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

Это не значит, что повторное бросание не имеет смысла. Например, если вы хотите обработать все исключения, кроме FooBarExceptions, вы можете написать:

try {
    // bad code 
} catch (FooBarException e) {
    throw e;
} catch (Exception e) {
    e.printStackTrace();
}

Или, если решение обработать исключение является более сложным, чем просто проверка его типа, вы можете просто его перехватить и перебросить, если окажется, что вы не можете его обработать:

for (int attempts = 0; attemps < 6; attempts++) {
    try {
        return crankyMethod();
    } catch (Exception e) {
        if (fatal(e)) {
            throw e;
        } else {
            // try again
            continue;
        }
    }
}

Стоит отметить, что когда люди говорят «бросить», некоторые имеют в виду другое исключение, как в следующем примере:

for (int i = 0; i < array.length; i++) {
    try {
        process(array[i]);
    } catch (Exception e) {
        throw new RuntimeException("Could not process element at index " + i, e);
    }
}

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

3 голосов
/ 08 марта 2012

Как уже говорили другие, в вашем примере нет разницы, и следует избегать второй формы.

Единственное место, где это иногда имеет смысл, - это то, где вам нужно поймать некоторые исключения и позволить другим броситься вверх. Поскольку синтаксис обработки исключений в Java ограничен, иногда вы можете сделать это:

try {
   somePieceOfCode();
} catch( RuntimeException e ) {
   throw e;
} catch( Exception e ) {
   handleException(e);
}

Это иногда делается, если somePieceOfCode выдает несколько различных проверенных исключений, которые не имеют общего базового класса (кроме Exception), но должны обрабатываться таким же образом. Возможно, вы не захотите просто поймать Exception, потому что это также поймает такие вещи, как NullPointerException, и вы можете предпочесть, чтобы эти исключения всплыли как есть.

Этот код позволит всем RuntimeExceptions пузыриться вверх, но обрабатывает все другие исключения.

Эта идиома немного необычна, и не всем она нравится, но вы можете увидеть ее в некоторых местах.

1 голос
/ 08 марта 2012

Стандартные причины для перехвата и исключения:

  1. Для регистрации инцидента и исключения.
  2. Выполнить некоторую очистку из-за исключения (но часто лучше сделать в блоке finally).
  3. Чтобы обернуть исключение в более подходящее исключение (т. Е. Для вашего метода processAccount (), вероятно, более целесообразно выбрасывать исключение AccountException (или какое-либо подобное) вместо DbException).
1 голос
/ 08 марта 2012

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

С учетом сказанного, вы, как правило, не должны использовать эту технику, потому что

  • Он объединяет ваш код без дополнительной выгоды (при нормальных обстоятельствах)
  • Вы должны использовать блоки try-catch только там, где это действительно необходимо, поскольку это может замедлить выполнение
0 голосов
/ 08 марта 2012

Одним из основных преимуществ перехвата и повторного выброса является перенос исключения в другое, специфичное для домена исключение, поэтому вызывающему коду не нужно беспокоиться о проблемах, связанных с реализацией, и он может просто перехватывать исключение, специфичное для библиотеки.

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

Hibernate перехватывает универсальное исключение SQLException, а затем проверяет объект, чтобы определить истинную причину исключения, перед тем, как поместить его в специфическое исключение Hibernate, которое более точно описывает, в чем причина проблемы.

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

0 голосов
/ 08 марта 2012

Я не думаю, что есть большая разница, но за то, что это стоит, я бы предпочел первый.

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

Просто ловить и перебрасывать - пустая трата нажатий клавиш.Это не добавляет никакой информации и не делает ничего конструктивного.

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

0 голосов
/ 08 марта 2012

Разницы нет.Если вы не хотите что-то с этим сделать (исключение), прежде чем перебрасывать это.

...