Чи не є хорошою практикою обробляти винятки з виконання коду в коді?


11

Я працюю над додатком Java, і я бачу, що винятки з виконання часу обробляються в багатьох місцях. Наприклад,

try {
    // do something
} catch(NullPointerException e) {
    return null;
}

Мої запитання полягають у тому, коли корисно обробляти винятки під час виконання програми? Коли винятки слід залишати без змін?


7
-1: Єдиної відповіді на питання, яке є таким широким і розпливчастим, немає. Неможливо дати однозначну відповідь на питання, настільки зосереджене, як це. Це питання жахливе. Надайте конкретні приклади, коли у вас є сумніви.
S.Lott

@ S.Lott Я не погоджуюся в цьому випадку, оскільки, здається, існує підмножина програмістів, які мають у своєму голові, що це так, не маючи «хорошої» раціональності.
SoylentGray

2
@Chad: "У цьому випадку немає раціональної" хорошої "раціональності. Це може бути правдою. Але єдиною можливою відповіддю має бути "це залежить". Тому питання видається несправним.
S.Lott

Відповіді:


18

Це залежить.

Наприклад, Integer#parseIntкидки NumberFormatException(що є RTE), якщо поданий рядок неможливо проаналізувати. Але напевно ви не хочете, щоб ваш додаток вийшов з ладу лише тому, що користувач написав "х" у текстове поле, яке було для цілих чисел? І звідки ви знаєте, чи можна проаналізувати рядок, якщо ви не спробуєте розібрати її спочатку? Тож у цьому випадку RTE - це лише сигнал про помилку, який повинен викликати якесь повідомлення про помилку. Можна стверджувати, що це повинен бути перевірений виняток, але що ви можете зробити - це не так.


2
Я погоджуюся з "Це залежить", але ваш приклад розбору здається скоріше випадком поганого дизайну API. Integer#parseIntПотрібно дійсно повернути Maybe<Integer>замість цього і взагалі не кидати жодного винятку.
Йорг W Міттаг

3
@ Йорг W Міттаг: Я погоджуюся, що це поганий дизайн API, але ми маємо мати справу з реальним світом. Як правильно поводитися з викидними / повернутими значеннями, залежить від того, як насправді працює світ , а не від того, як він повинен оптимально працювати :-)
Joonas Pulakka

Справа в тому, що ви можете зробити щось значуще для передбачуваної умови (введення користувача не ціле число). Просто ковтання NPE - це поганий стиль і просто приховає наявні помилки програмування.
Юрген Стробель

7

NullPointerExceptions зазвичай є ознакою відсутньої перевірки нуля. Отже, замість того, щоб це ловити таким чином, вам слід додати відповідний нульовий чек, щоб переконатися, що ви не викинете виняток.

Але іноді доцільно обробляти RunTimeExceptions. Наприклад, коли ви не можете змінити код, щоб додати нульову перевірку у відповідному місці, або коли виняток є чимось іншим, ніж NullPointerException.

Ваш приклад поводження з винятками - жахливий. Роблячи це, ви втрачаєте слід стека та точну інформацію про проблему. І ви насправді не вирішуєте це, оскільки, ймовірно, ви запустите іншу NullPointerException в іншому місці та отримаєте оманливу інформацію про те, що сталося та як вирішити це.


1
Я хотів би додати, що нульова перевірка є кращою ефективністю рішення.
Махмуд Хоссам

... все-таки, якщо ви робите десятки асигнувань, які "ніколи не повинні провалюватися" навколо одного місця, додавання нульових чеків для кожного з них може смішно заплутати код. Виняток із загальної точки зору (що ВІЛЬКО вирішить ситуацію, а не просто return null;) стане кращим рішенням.
СФ.

Ви, мабуть, плутаєте java з чимось іншим (C ++ для зразка). Коли розподіл не вдається, ви отримуєте OutOfMemoryError або щось подібне, ніколи не нульовий покажчик. Приховування нульового повернення замість винятку - це приховування помилки в очікуванні вибуху коду десь в іншому місці.
deadalnix

newкидки std::bad_allocв C ++.
Р. Мартіньо Фернандес

Якщо припустити, що новий оператор не перевантажений, що є звичайною практикою. У C ++ може статися все, що завгодно;) Але гаразд, скажімо, мальчик С. Важливим моментом було те, що ти ніколи цього не отримував у Java.
deadalnix

4

Я обробляю очікувані винятки там, де я їх очікую. (Як і помилки читання / запису БД). Несподівані винятки я піднімаю. Десь ще можна очікувати винятку і мати логіку для цього.


2

Винятки мають бути лише такими .. винятками. Найкращою практикою при використанні винятків є використання їх для висвітлення ситуації, в якій трапляється щось, що суперечить тому, що ви б очікували, що трапиться. Класичний приклад - FileNotFoundException, який викидається, коли файлу просто немає. Якщо ви тестуєте існування файлу, тоді ви використовуєте File.exists (), оскільки ви просто продаєтеся 10-футовою паличкою, щоб побачити, чи вдарили ви щось.

Ви технічно можете досягти тих же результатів, оточуючи їх у спробі лову та використовуючи файл, як ніби він існує, але А) винятки, як правило, дорого витратні на ресурси, і B) програмісти припускають, що ви мали на увазі, що файл існував, якщо він був у випробуванні, що додає загальній плутанині програми.

Є багато ситуацій, в яких я напишу метод, який отримує якесь значення з бази даних. Тисяча речей може піти не так, і, дивлячись, як мені потрібна лише одна невелика інформація, незручно оточувати виклик списком спробу вловлювання, який містить 5 різних винятків. Тож я виберу винятки в методі отримання. Якщо щось піде не так, я вживаю будь-яких відповідних дій, щоб закрити підключення до бази даних чи що-небудь в остаточному пункті та повернути null. Це хороша практика не лише тому, що вона спрощує ваш код, але й тому, що "null" надсилає те саме повідомлення, яке ви могли отримати від винятку .. що щось не пішло, як було заплановано. Керуйте специфікою виключень у методі отримання, але керуйте, що робити, коли речі не роблять '

Наприклад:

Integer getUserCount() {
   Integer result = null;
   try {
      // Attempt to open database and retrieve data
   } catch (TimeoutException e) {
      logger.error("Got a watch?");
   } catch (MissingDatabaseException e) {
      logger.error("What are you smoking?");
   } catch (PermissionsToReadException e) {
      logger.error("Did you *really* think you were getting away with that?");
   } catch (PressedSendButtonToHardException e) {
      logger.error("Seriously.. just back away from the computer... slowly..");
   } catch (WTFException e) {
      logger.error("You're on your own with this one.. I don't even know what happened..");
   } finally {
      // Close connections and whatnot
   }
   return result;
}

void doStuff() {
   Integer result = getUserCount();
   if(result != null) {
       // Went as planned..
   }
}

6
Якщо ви використовуєте File.exists () і покладаєтесь на результат, стан гонки може статися, якщо файл буде видалено прямо між File.exists () та File.open (). Якщо це викликає помилку, критично важливу для безпеки, зловмисник може навмисно спричинити цей стан. Через це іноді краще тримати операцію атомарною, тобто спробувати її і зловити виняток.
користувач281377

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

Це погане рішення повернути нуль. Це призведе до NullPointerException в якийсь момент і буде дуже важко налагодити те, що пішло не так. Тому що хтось в якийсь момент забуде нульову перевірку.
deadalnix

@deadalnix: Я можу стверджувати, що ви можете так само легко забути оточитись із пробним ловом в іншому випадку. Різниця - це питання стилю, а не функціоналу.
Ніл

@ammoQ: Я не згоден. Я думаю, ви повинні використовувати File.exists (), і за рідкісних обставин, які він видаляється перед його використанням, виняток є більш ніж доречним. Різниця полягає в тому, де ви тримаєте свій улов. Просто створіть ловець винятків ковдр для непередбачених помилок, щоб увійти та повідомити про це.
Ніл

-5

так, ви правильно обробляєте винятки з часу запуску, це не є хорошою практикою. Причиною є те, що це вважається дорогим / великим обсягом пам'яті.


5
Вітаю, прассе, чи можете ви детальніше розказати свою відповідь? Однокласники, які не підкріплені фактами, посиланнями чи досвідом, не дуже корисні.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.