Кидки або спроба зловити


77

Яке загальне емпіричне правило при вирішенні питання про додавання throwsречення до методу чи використання символу try-catch?

З того, що я сам прочитав, throwsслід використовувати, коли абонент порушив свій кінець договору (переданий об'єкт), а try-catchслід використовувати, коли відбувається виняток під час операції, що виконується всередині методу. Це правильно? Якщо так, що робити з боку, хто телефонує?

PS: Шукали через Google та SO, але хотіли б отримати чітку відповідь на це.


4
Я завжди був шанувальником підходу "Якщо має сенс з цим розібратися тут ... тоді зроби це".
CheesePls

Мені подобається, коли всі мої винятки обробляються там, де вони трапляються, тому мені не доводиться мати справу з дорогою.
Дуг Хауф,

Відповіді:


58
  • ловіть виняток лише в тому випадку, якщо ви можете впоратися із цим змістовно
  • оголосити про викид винятку вгору, якщо він повинен оброблятися споживачем поточного методу
  • викидати винятки, якщо вони спричинені вхідними параметрами (але їх частіше не встановлюють)

Правильно, третє правило дуже чітке. Щодо значущої обробки винятків, чи це стосується вищих рівнів програми? Чи означає це, що API зазвичай мають викиди? Крім того, у яких випадках метод повинен відновити винятки, що надходять із підметодів (наприклад, із приватних корисних методів)?
James P.

ну, це дуже залежить. API викидає винятки, так. Але потім приходить вибір перевіреного проти неперевіреного.
Божо

3
Навіщо поновлювати виняток? Тільки не ловіть і не передайте його в стек дзвінків.
Стів Куо,

15

Загалом, метод повинен викликати виняток для свого абонента, коли він не може обробляти пов'язану проблему локально. Наприклад, якщо метод повинен читати з файлу із заданим шляхом, IOExceptionsне можна обробляти його локально розумним способом. Те саме стосується недійсного введення, додаючи, що моїм особистим вибором було б створити неперевірений виняток, як IllegalArgumentExceptionу цьому випадку.

І він повинен вловити виняток із викликаного методу, якщо:

  • це те, що може бути оброблено локально (наприклад, спроба перетворити вхідний рядок у число, і якщо перетворення не вдається, цілком допустимо повернути значення за замовчуванням),
  • або його не слід кидати (наприклад, якщо виняток надходить із конкретного нижчого рівня, реалізація якого не повинна бути видимою для абонента - наприклад, я не хочу показувати, що моє DAOвикористання Hibernateдля збереження моїх сутностей, тому Я ловлю все HibernateExceptionsлокально і перетворюю їх у власні типи винятків).

Гаразд. Для переформулювання буде вилучено виняток, коли негайне рішення неможливе, і потрібна певна взаємодія «вище», щоб вирішити, що робити. Крім того, виняток не буде відновлено, якщо він має лише "значення" між групою класів, і на його місці слід створити більш узагальнений виняток, щоб повідомити абоненту про необхідність уваги. Це звучить більш-менш правильно?
James P.

1
@James, більш-менш :-) Якщо під "взаємодією" ви маєте на увазі запитання про втручання користувача, це не завжди потрібно. Крім того, замість "більш узагальненого" я віддав би перевагу "іншому". Визначений користувачем ConnectionException є не більш загальним, ніж HibernateException.
Péter Török

11

Ось спосіб використання:

Кидки:

  • Ви просто хочете, щоб код зупинився при виникненні помилки.
  • Добре з методами, схильними до помилок, якщо певні передумови не виконуються.

Try-Catch:

  • Коли ви хочете, щоб програма поводилася по-різному з різними помилками.
  • Чудово, якщо ви хочете надати значущі помилки кінцевим користувачам.

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


Ви майже НІКОЛИ не повинні використовувати обробку винятків для управління програмою. Це жахлива практика.
CheesePls

2
Існує також Try-catch-rethrow або try-catch-wrap-throw - тобто те, що ти можеш обробляти виняток значущим чином, не означає, що ти закінчив. Метод повинен виконувати те, що вказує його назва, або повинен створити виняток: abstractions-r-us.blogspot.com/2010/06/… . (безсоромна вилка для мого блогу)
jyoungdev

1
Це питання, яке я задавався вже якийсь час. Я думаю, що я намагаюся використовувати блоки спробного лову, якщо потрібно, з визначеними користувачем винятками. Виняток. Але мені доведеться сказати, що вкидання заглушки методу є набагато чистішим і набагато меншим кодом, який доведеться сортувати пізніше, якщо вам доведеться робити налагодження. Якщо ви використовуєте мета в заглушці методу, вам доведеться зафіксувати помилку вгору по ланцюжку методів, я думаю, в цьому я не впевнений. За допомогою try-catch ви можете просто отримати try-catch-помилку, не передаючи її по ланцюжку методів. Я не повністю впевнений у цьому, але я думаю
Дуг Хауф,

Я думаю, що це взагалі так. Я знаю, що при читанні файлів, якщо ви використовуєте функцію try-catch, а потім оголошуєте екземпляр свого класу в іншому класі, вам не потрібно, щоб метод кидав виняток. Я все ще не впевнений у цьому.
Дуг Хауф,

9

Моє персональне емпіричне правило для цього просте:

  • Чи можу я впоратись із цим змістовно (додано з коментаря)? Тож вставте код try/catch. Обробляючи це, я маю на увазі можливість повідомити користувача / відновитись після помилки або, в ширшому розумінні, мати можливість зрозуміти, як цей виняток впливає на виконання мого коду.
  • В іншому місці викинь його

Примітка: ці відповіді тепер є вікі спільноти. Не соромтеся додавати більше інформації в.


6
Чи можу я впоратись із цим змістовно ?
Nivas

2
Які ваші критерії для вирішення, чи можете ви обробляти винятки локально? Це на тому рівні, де ви насправді можете подбати про виняток і показати повідомлення, наприклад?
James P.

Викидати це - погана ідея. Краще передати його в стек дзвінків.
Стів Куо,

3

Рішення про додавання пропозиції try-catch або throws до ваших методів залежить від того, "як ви хочете (або повинні) обробляти ваші винятки".

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

Тож відповідаючи на ваші запитання, не існує принципового правила.

Ви повинні вирішити, де ви хочете обробляти виняток, і це рішення, як правило, дуже специфічне для вашого домену та вимог програми.


2

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


Чи завжди ви пишете виняток помилки у файл реєстратора або на консоль. Я думав про це вчора ввечері, тому що в власне програмі ви не зможете побачити фактичну консоль, тому ваші помилки не повинні переходити до текстового файлу. Отже, як друкує e.printStackTrace (). Я переходжу до консолі під час налагодження, але чи можна ще перейти до неї?
Дуг Хауф,

1

Метод повинен бути лише throwsвинятком, якщо він може надати обґрунтовані гарантії стану об'єкта, будь-яких параметрів, переданих методу, та будь-яких інших об'єктів, на які діє метод. Наприклад, метод, який повинен отримати з колекції елемент, який абонент очікує міститися в ньому, може throwsмати перевірене виняток, якщо елемент, який, як очікувалося, існує в колекції, цього не робить. Абонент, який виявив цей виняток, повинен очікувати, що колекція не містить відповідного елемента.

Зауважте, що хоча Java дозволить перевіреним виняткам виділятися через метод, який оголошено як викид відповідних типів, таке використання, як правило, слід розглядати як анти-шаблон. Уявіть, наприклад, що якийсь метод LookAtSky()оголошений як виклик FullMoonException, і очікується, що він викине його, коли Місяць заповниться; уявіть далі, що LookAtSky()дзвінки ExamineJupiter(), які також оголошено як throws FullMoonException. Якщо a FullMoonExceptionбув кинутий ExamineJupiter(), і якщо LookAtSky()не впіймав його, або обробив його, або загорнув у якийсь інший тип винятку, код, який викликав LookAtSky, припускав би, що виняток був результатом заповнення місяця Землі; він не мав би поняття, що винуватцем може бути один із супутників Юпітера.

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


1

Коли використовувати що. Я багато шукав про це. Жорсткого правила немає.

"Але як розробник, перевірені винятки повинні бути включені в пропозицію методу throws. Це необхідно для того, щоб компілятор знав, які виключення перевірити. За домовленістю, неперевірені винятки не повинні бути включені в пункт" броски ".
Включення їх розглядається як погана практика програмування. Компілятор розглядає їх як коментарі і не перевіряє їх ".

Джерело: книга SCJP 6 Кеті Сьєрри


0

Якщо ви використовуєте try catch, коли виникає виняток, інші коди все одно будуть виконуватися.

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


0

пара try-catch використовується, коли ви хочете надати налаштування поведінки, у випадку, якщо виникає виняток ..... іншими словами ... у вас є рішення вашої проблеми (виникнення винятків) відповідно до вимог вашої програми .... .

Але throws використовується, коли у вас немає якогось конкретного рішення щодо випадку виникнення винятків ... ви просто не хочете отримувати ненормальне припинення вашої програми ....

Сподіваюся, це правильно :-)

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