Многократная или одиночная попытка поймать - PullRequest
49 голосов
/ 29 декабря 2010

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

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

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

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

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

//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
}

Ответы [ 12 ]

50 голосов
/ 29 декабря 2010

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

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

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

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

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

46 голосов
/ 29 декабря 2010

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

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

Сценарий 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 вместо отображения константыstring, displayt SomeException.toString или SomeException.getMessage.

4 голосов
/ 29 декабря 2010

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

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

1 голос
/ 05 августа 2014

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

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

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

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

1 голос
/ 29 декабря 2010

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

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

0 голосов
/ 04 июля 2017

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

0 голосов
/ 04 мая 2012

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

0 голосов
/ 29 декабря 2010

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

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

0 голосов
/ 29 декабря 2010

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

...