2010-12-29 4 views
43

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

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

Вопрос в этом ... есть ли недостаток в этом? Могут ли быть проблемы с производительностью или какой-либо другой скрытый монстр, которого я не вижу?

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

Просто, чтобы лучше проиллюстрировать мою точку зрения вот некоторые псевдо-код

//multiple try catch for same exception 
try { 
    //some code here 
} catch (MyException e) { 
    //specific error message here 
} 
try { 
    //some different code here 
} catch (MyException e) { 
    //more specific error message indicating a different issue 
} 
+1

Кажется, вам кажется, что вам нужно написать сообщение об ошибке для каждого вызванного исключения, рядом с точкой, в которой она была выбрана. Но почему? Часто единственной важной информацией является то, что операция в целом не удалась. – Raedwald

+1

@ Raedwald: Мне кажется, что добавление дополнительной информации о том, почему операция не удалась, будет полезна для обслуживания людей, которые работают после меня. Я использую плагины с открытым исходным кодом, поэтому для тех, кто их не знает, я могу добавить немного больше деталей. – Shaded

+3

Вот почему регистрация важна, затенена. Вам не нужно загружать код с конкретной обработкой ошибок, если, как предлагает Raedwalk, восстановление в любом случае безнадежно. Моя общая техника заключается в том, чтобы регистрировать все, что, по моему мнению, важно, и реконструировать Исключение. На самом деле, если ошибка безнадежна, я повторно выбрал исключение Runtime и поймал его на самом высоком уровне для окончательной очистки. –

ответ

46

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

try { 
    firstBatchOfTricky(); 
    secondBatchOfTricky(); 
    .... 
    nthBatchOfTricky(); 
} catch (ItWentBoomException e) { 
    // recover from boom 
} catch (ItWentBangException e) { 
    // recover from bang 
} 

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

Поскольку у вас есть собственный тип исключения, вы можете добавить данные, необходимые для исключения, чтобы делать разные вещи в блоке catch. Когда вы говорите «более конкретное сообщение», вы можете просто выбросить исключение с подробным сообщением; вам не нужно использовать несколько блоков catch. Если вы хотите сделать совершенно разные вещи в зависимости от состояния исключения, просто создайте больше типов исключений и блоков catch, но только один блок try, так как мой псевдокод показывает ...

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

+0

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

+0

Будьте осторожны при реорганизации, чтобы не изменять поведение вашего кода. Например, если раньше у вас было два блока try/catch, скажите A и B, и код в A обрабатывался без повторного сверления, тогда код в B будет выполнен. Если вы просто объедините два таких блока в одно, это поведение изменится, если A выдает исключение, тогда B больше не будет выполняться. Удачи рефакторингу! – rodion

+0

У меня есть один вопрос на мой взгляд, что, если мы поймаем обобщенное исключение i-e Исключение в блоке catch вместе с этими исключениями? ... будет ли код выполнен правильно? или все исключения затем перейдут в этот блок catch, который будет захватывать исключение верхнего уровня «Исключение»? или будет какое-то исключение времени компиляции/времени выполнения? –

4

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

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

+0

Да, но я стрелял больше, что, если в одном блоке try у меня есть две строки, которые бросают один и тот же тип исключения. – Shaded

+0

Если вы обращаетесь с ними по-другому, то хорошо иметь два блока catch. Но это вызывает вопросы, которые преследуют многие другие ответы. – jzd

+0

Я полностью согласен, спасибо за то, что вы ответили иначе: D – Shaded

1

Мои личные предпочтения - это одна попытка, которая может иметь или не иметь несколько блоков блокировки. Мои методы, как правило, достаточно малы, если это имеет смысл. Если у вас слишком много времени, чтобы это было практично, возможно, вам нужно подумать о рефакторинге.

Одна вещь в блоках catch: если ваш блок catch печатает или регистрирует трассировку стека и перебрасывает, я бы сказал, что вам лучше добавить исключение в предложение throws в подписи метода и позволить ему пузыриться вверх.

0

Отличный вопрос. Я собираюсь сказать, что вы должны использовать один блок try-catch. Мое рассуждение: если у вас есть причина разделить ваш метод на несколько блоков try-catch, вероятно, вам стоит подумать о реорганизации вашего метода в несколько методов, каждый из которых имеет свой собственный блок try-catch.

0

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

0

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

0

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

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

1

Я согласен с общим консенсусом вышеуказанных ответов, что один блок try-catch лучше. Однако, к тому времени, когда ваш метод достаточно длинный, чтобы вы рассматривали этот вопрос, это, вероятно, слишком долго. И может быть проще извлечь из него новые методы, если обработка исключений более локализована. Тем не менее, я считаю, что лучшим вариантом может быть извлечение методов, которые просто бросают исключение и оставляют обработку исключений на месте, в исходном методе - идеально в одном блоке try-catch.

38

Это не вопрос производительности или личных предпочтений. Это вопрос функциональности и требований.

Предположим, я пишу:

Сценарий 1:

try 
{ 
    doThingA(); 
} 
catch (SomeException panic) 
{ 
    System.out.println("doThingA failed"); 
} 
try 
{ 
    doThingB(); 
} 
catch (SomeException panic) 
{ 
    System.out.println("doThingB failed"); 
} 

Сценарий 2:

try 
{ 
    doThingA(); 
    doThingB(); 
} 
catch (SomeException panic) 
{ 
    System.out.println("doThingA or doThingB failed"); 
} 

Эти два сценария не являются эквивалентными: Они делают разные вещи. В сценарии 1, если doThingA выбрасывает исключение, doThingB все еще выполняет. В сценарии 2, если doThingA выбрасывает исключение, doThingB не выполняется. Таким образом, вопрос заключается не в том, что дает лучшую производительность, или что более читаемый код, а скорее, если doThingA терпит неудачу, должен ли doThingB выполняться или нет?

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

void doThingA() throws SomeException 
{ 
    ... whatever code ... 
    if (theWorldIsAboutToEnd) 
    throw new SomeException("doThingA failed"); 
} 

Затем в предложении catch вместо отображения постоянной строки отобразится SomeException.toString или SomeException.getMessage.

+0

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

+0

Тогда у вас не может быть двух небольших уловов. Это не сработает. Если первый блок try встретит исключение, второй блок try все равно будет выполнен. – Jay

+3

отлично, на самом деле я точно искал оба этих сценария, которые нужно решить. – khurramengr

0

Это очень старый вопрос. Но мой ответ заставит его сделать это, потому что в последние дни Java 7 добавила новую функцию для добавления нескольких исключений и блока catch. Это устранит много кода и выглядит очень интересно. Я сталкивался с этим link, размышляя о концепции try-with-resource.

1

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

Однако, сказав, что использование множителей блоков try/catch намного лучше, на мой взгляд.Использование большого try/catch похоже на использование нескольких операторов goto, за исключением того, что вы не можете определить, откуда идут gotos.

Например, как вы можете определить, какой метод будет отправляться на исключение1, и который перейдет к исключению 2? Это нормально, если это небольшой блок, но как только он становится больше, он становится очень нечитаемым.

try{ 
    doThing1(); 
    doThing2(); 
    doThing3(); 
    doThing4(); 
    doThing5(); 
    doThing6(); 
    doThing7(); 
    doThing8(); 
    doThing9(); 
} catch (Exception1 e){ 

} catch (Exception2 e){ 

} 

Ниже яснее.

try{ 
    doThing1();  
} catch (Exception1 e){ [...] } 
    doThing2(); 
    doThing3(); 
    doThing4(); 
    doThing5(); 
    doThing6(); 
    doThing7(); 
    doThing8(); 
try{ 
    doThing9(); 
} catch (Exception2 e){ [...] } 
0

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

Смежные вопросы