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

Несколько или однопользовательские попытки поймать

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

В настоящее время у меня есть один блок catch catch над большинством моего метода, и он обрабатывает несколько отдельных исключений в конце, но я решил, что больше блоков 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
}
4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

Сценарий 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.

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

Например, как показано ниже, как вы можете определить, какой метод будет отправляться в exception1, и который перейдет к исключению 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){ [...] }

Ответ 7

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

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

Ответ 11

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

Ответ 12

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