Кілька спроб-лову чи одна?


77

Зазвичай я б зробив це:

try
{
    code

    code that might throw an anticipated exception you want to handle

    code

    code that might throw an anticipated exception you want to handle

    code
}
catch 
{

}

Чи є якісь переваги робити це таким чином?

code

try
{
    code that might throw an anticipated exception you want to handle
}
catch
{
}

code

try
{
    code that might throw an anticipated exception you want to handle
}
catch
{
}

code

Оновлення:

Я спочатку задав це запитання з посиланням на C #, але, як прокоментував А. Леві, воно могло застосовуватися до будь-якої мови обробки винятків, тому я змусив теги це відображати.


7
Ви хочете, щоб обробка зупинилася, як тільки сталася перша помилка (перший приклад), або вона може продовжуватися, навіть якщо частина обробки не вдається (інша)?
David Pratte

2
@DLP - Я хотів би, щоб він припинив обробку - я бачу, хтось згадав це після вас. Це хороший момент.
Стів

4
Хоча ви позначили це тегами як C # та .net, я думаю, що це насправді агностик мови. Це питання стосується будь-якої мови за винятком, таких як Java, C ++, JavaScript, OCaml, F #, Python, Clojure тощо. Це також стосуватиметься системи стану / перезапуску в Common Lisp та інших інших Lisps. Тож я б попросив вас зробити цю мову агностичною ... Однак ваш дзвінок.
А. Леві

Відповіді:


88

Це залежить. Якщо ви хочете забезпечити спеціальну обробку для конкретних помилок, використовуйте кілька блоків catch:

try
{ 
    // code that throws an exception
    // this line won't execute
}
catch (StackOverflowException ex)
{
    // special handling for StackOverflowException 
}
catch (Exception ex)
{
   // all others
}

Якщо, однак, метою є обробка винятку та продовження виконання, розмістіть код в окремих блоках спроби-лову:

try
{ 
    // code that throws an exception

}
catch (Exception ex)
{
   // handle
}

try
{ 
    // this code will execute unless the previous catch block 
    // throws an exception (re-throw or new exception) 
}
catch (Exception ex)
{
   // handle
}

4
+1, виділене в першому прикладі, переконайтеся, що обробник загальних винятків є останнім у декларації, щоб ви обробляли спочатку конкретні, а потім будь-що інше, що знаходиться поза вашим контролем, оброблялося загальним чином.
leeroya

Як зазначено тут: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… , використання умовного улову є нестандартним і не відповідає стандартним напрямкам. Не використовуйте його на виробничих сайтах, що стоять перед Інтернетом: це буде працювати не для кожного користувача. Також можуть бути великі несумісності між реалізаціями, і поведінка може змінитися в майбутньому.
JLavoie

16

Якби я міг вибрати другу, я б, можливо, розділив це на дві функції.


5
+1: Я повністю згоден, хоча, мабуть, я б написав це як "Якби я міг вибрати другий, я б ..", оскільки я вважаю, що це правильно робити в будь-який час, коли це можливо ...
Рід Копсі

11

Ні, просто використовуйте декілька блоків catch для конкретних винятків (якщо в блоці немає лише тонни коду і лише пара рядків може створити виняток. У цьому випадку я б пішов з другим методом).


9

Ви думаєте про це неправильно. Що потрібно робити у блоках улову? Якщо ви оговтаєтесь від будь-якого з можливих винятків, запустивши той самий код, незалежно від того, яка операція викинула виняток, використовуйте один блок catch. Якщо вам потрібно виконати різні операції очищення залежно від того, яку операцію кинули, тоді використовуйте кілька блоків лову.

Крім того, якщо ви можете використовувати try / нарешті або шаблон RAII замість try / catch, тоді вам слід.


4

На мій погляд, другий метод кращий, оскільки він дозволяє з більшою точністю фіксувати помилки.

Також обгортання всього коду всередину одного великого блоку try / catch - це погано, якщо у вашої програми є якась проблема, і вона аварійно завершує роботу, але оскільки ви захопили велике загальне виняток, то ймовірність того, що ви зможете насправді правильно з ним впоратися, нижча. Ви повинні мати конкретні частини всередині try catch, наприклад, якщо ви читаєте файл або берете введення користувача. Таким чином ви можете краще впоратися з цим винятком


2

Я віддаю перевагу другому методу - це полегшує налагодження, точнішу обробку помилок, а також приємно подає тестування вашого блоку.


2

Я б вибрав другий варіант, але щоразу, коли я бачу цей шаблон коду, моє перше відчуття полягає в тому, щоб подумати про розподіл його на кілька функцій / методів. Очевидно, чи робити це, залежить від того, що робить код;)


2

Це залежить від характеру типу помилок у вашому коді.

  1. Якщо обробка тих помилок, які ви збираєтеся зробити, однакова, виконайте одну спробу ... ловіть для цієї групи коду. В іншому випадку це буде занадто нудно.

  2. Якщо помилки вимагали іншого поводження, відокремте його, тому що ви повинні.

НЕ ЗАСТОСОВУЙТЕ ОДИНИЙ МЕТОД ДЛЯ ВСІХ СПРАВ. ПРОГРАМУВАННЯ БІЛЬШІ ЧАСУ КОНТЕКСТУ СПЕЦИФІЧНИЙ :)

Вам потрібно досягти балансу "ДОБРО / КОМПЛЕКС" і "ПОГОРО / ПРОСТО". Чим більше ви кодуєте, тим менше будете застрягати в такій дилемі :)

Щасливого програмування!


2
Взагалі, це погана форма - писати ціле речення з великими літерами. Але врешті-решт, це специфічно контекст
Джо Філліпс

1

Другий метод. Зберігання коду, який може спричинити виняток, окремо від іншого коду - зменшує розмір розділу та полегшує управління, замість того, щоб обертати весь код, навіть той, який не створюватиме винятків.


1

Є час, коли ми хочемо показати конкретну помилку користувачеві.

try{
   try{
      ... send message
   }
   catch(exception e){
    ...log error
    ...rethrow  send related error/show custom error
   }
   try{
       ...try to receive response
   }
   catch(exception e){
       ...show receive related error
   }
   //finally close the connection
   }finally{
        ...close connection
   }

-1

Другий спосіб, але в ідеалі використовувати захисні коди - спробувати / зловити може бути дорого, якщо ви вловите виняток.


2
Спробувати / зловити в C # насправді не дуже дорого, якщо ви насправді щось не зловите ...
Рід Копсі,

2
PS: Я усвідомлюю, що цій відповіді 7 років, але я хочу поставити її в контексті 2017 року .... Показник продуктивності Try / Catch значно перевищений цитатами, і вигаданий приріст продуктивності НІКОЛИ не є вагомою причиною для кращого, надійнішого коду, особливо коли ви усвідомлюєте, коли .NET вийшов найкращим комп’ютером, який ви могли придбати, був Pentium 4 із 1–2 ГБ оперативної пам’яті, і сьогодні у нас є 4 ядра з гіперпотоками, це швидкість більше ніж у 8 разів, і 8-16 ГБ оперативної пам’яті є нормою. Крім того, скомпільований код .NET також швидший, ніж 15 років тому, навіть на тому самому обладнанні. Виклик "Спробувати / зловити повільно" - це міф, і його потрібно припинити.
TravisO
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.