Розуміння перевірених та неперевірених винятків на Java


703

Джошуа Блох в " Ефективній Java " сказав це

Використовуйте перевірені винятки для відновлюваних умов та виключень під час виконання програм для помилок програмування (Пункт 58 у другій редакції)

Подивимось, чи я правильно це розумію.

Ось моє розуміння перевіреного винятку:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Чи вважається вище перевіреним винятком?

2. Чи RuntimeException є неперевіреним винятком?

Ось моє розуміння неперевіреного винятку:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Тепер, чи не міг вищезазначений код бути перевіреним винятком? Я можу спробувати відновити подібну ситуацію? Можу я? (Примітка: моє третє запитання знаходиться у catchвищезазначеному)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. Чому люди роблять це?

public void someMethod throws Exception{

}

Чому вони пускають виняток на пульс? Чи не краще поправити помилку раніше? Чому бульбашки?

6. Чи слід міхурити точний виняток або замаскувати його за допомогою винятку?

Нижче мої читання

Коли в Java потрібно створити перевірений виняток, і коли це повинен бути виняток під час виконання?

Коли вибирати перевірені та неперевірені винятки


6
Я маю чудовий приклад неперевіреного винятку. У мене є DataSeriesклас, у якому зберігаються дані, які завжди повинні залишатися у часовому порядку. Існує спосіб додати нове DataPointдо кінця DataSeries. Якщо весь мій код працює правильно впродовж проекту, його DataPointне слід додавати до кінця, який має попередню дату до тієї, яка вже закінчується. Кожен модуль у всьому проекті будується з цією істиною. Однак я перевіряю цю умову і кидаю неперевірений виняток, якщо це трапилося. Чому? Якщо це трапиться, я хочу знати, хто це робить, і виправити це.
Ерік Робертсон

3
Щоб додати ще більше плутанини. Багато людей виступають за перевірені винятки ~ 10 років тому, але погляди сьогодні все більше рухаються до "перевірених винятків - це погано". (Але я з цим не згоден)
Кай

10
Користуватися обробкою винятку корисно лише тоді, коли ви маєте щось із цим корисним, інакше ви повинні дозволити абоненту впоратися з цим. Записувати його і робити вигляд, що цього не сталося, як правило, не корисно. Просто перекидати це безглуздо. Обгортання в RuntimeException не настільки корисне, як думають деякі, воно просто змушує компілятор перестати вам допомагати. (ІМХО)
Пітер Лорі

40
Ми повинні припинити використовувати всебічно оманливі умови перевірених / неперевірених винятків. Їх слід назвати чек санкціоновані проти чек-несанкціонованих винятків.
Блаженний Гек

3
Я також подумав, що abt ur 5-та загальнодоступна недійсна метода_імена кидає виняток {} чому деякі люди роблять це?
Maveň ツ

Відповіді:


475

Багато людей кажуть, що перевірені винятки (тобто такі, які ви повинні чітко виловити або повторно скинути), взагалі не повинні використовуватися. Наприклад, вони були усунені в C #, і більшість мов їх не мають. Таким чином, ви завжди можете кинути підклас RuntimeException(неперевірений виняток)

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

Ось мій розширений погляд на цю тему .

Щодо конкретних питань:

  1. Чи NumberFormatExceptionвважається перевіреним виключенням?
    NumberFormatExceptionне відмічено (= підклас RuntimeException). Чому? Не знаю. (але має бути метод isValidInteger(..))

  2. Чи RuntimeExceptionє неперевірений виняток?
    Так, саме.

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

    • запишіть його та поверніть
    • скинути його (оголосити, що його кинули методом)
    • побудуйте новий виняток, передавши поточний у конструктор
  4. Тепер, чи не міг вищезазначений код бути перевіреним винятком? Я можу спробувати відновити подібну ситуацію? Можу я?
    Це могло бути. Але ніщо не заважає тобі і зловити неперевірений виняток

  5. Чому люди додають клас Exceptionу пункті "кидки"?
    Найчастіше тому, що люди лінуються розглядати, що ловити, а що відкидати. Кидання Exception- погана практика, і її слід уникати.

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


36
Що стосується викидання винятку, то це не завжди тому, що люди ліниві, також звичайно, що ви, впроваджуючи рамки, дозволяєте користувачам фреймворку вміти кидати будь-які винятки. Наприклад, ви можете перевірити підпис інтерфейсу Callable в JSE
Kaj

10
@Kaj - так, такі загальні речі, як Callable, перехоплювачі та подібні - це особливі випадки. Але в більшості випадків це тому, що люди ліниві :)
Божо

7
re: 3.1 "запишіть його та поверніть" Робіть це розумно. Це дуже близько до їжі чи приховування та винятку. Я б зробив це для чогось, що не вказує на проблему, що насправді не є винятковою. Журнали занадто легко заповнюються та ігноруються.
Кріс

4
"коли ви хочете змусити користувача вашого API думати, як впоратися з надзвичайною ситуацією" - ви не можете змусити нікого думати, якщо вони цього не хочуть. Якщо вони не хочуть думати, вони напишуть поганий блок виключень, який взагалі нічого не робить, або, що ще гірше, видаляє або заважає критичній інформації про помилки. Ось чому перевірені винятки є невдачею.
adrianos

3
@adrianos "... ти нікого не можеш змусити думати, якщо вони не хочуть ...." За допомогою цього напряму мислення ми також могли б усунути помилки компіляції .... Я не дуже націлюю на тебе, я чув це аргументи знову і знову, і все ще вважають, що це найбідніше пояснення для маркування перевірених винятків як відмови. Як бічне зауваження, я раніше бачив таку мову, де компіляція (і фактично помилки виконання) насправді була неможлива завдяки проекту. Ця дорога вела до деяких дуже темних місць.
Ньютопський

233

Незалежно від того, чи є щось "перевіреним винятком", немає нічого спільного з тим, чи ви його ловите, або що ви робите в блоці вилову. Це властивість класів виключень. Все , що підклас Exception крім для RuntimeExceptionі його підкласи є перевіряється винятком.

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

Чому вони пускають виняток на пульс? Чи не впорається помилка швидше, тим краще? Чому бульбашки?

Тому що в цьому вся суть винятків. Без такої можливості вам не знадобляться винятки. Вони дозволяють вам обробляти помилки на обраному вами рівні, а не змушують вас боротися з ними методами низького рівня, де вони спочатку мають місце.


3
Дякую! Іноді я викидаю винятки зі своїх методів через принцип дерьмовості. Я, один із розробників моєї команди, хоче ввести невірний вираз xpath, щоб вирішити виняток. Навряд чи вони потрапляють на виняток, і нічого не роблять, вони почують про це під час перегляду коду.
jeremyjjbrown

12
"Все, що є підкласом Throwable, крім RuntimeException та його підкласів є перевіреним винятком." - Ваше твердження невірне. Помилка також успадковує Throwable, і вона не перевіряється.
Bartzilla

8
@JonasEicher: в основному, головна перевага винятків полягає в тому, що вони дозволяють вибирати, де в стеці викликів ви хочете обробляти помилки, які часто є досить високими, зберігаючи шари між ними повністю вільними від артефактів, що обробляють помилки. Перевірені винятки знищують саме таку перевагу. Інша проблема полягає в тому, що відмінність, що перевіряється / не перевіряється, прив'язується до класу виключень, який також представляє концептуальну категоризацію винятків - змішування двох аспектів, які не обов'язково пов'язані взагалі.
Майкл Боргвардт

2
"Але, здається, думка більшості полягає в тому, що проблем дизайну, які він створює, не варто". - Цитування, будь ласка?
Кервін

3
@Bartzilla Так. Для повноти, як Throwableговорить javadoc for : "Throwable та будь-який підклас Throwable, який також не є підкласом ні RuntimeException, ні помилки, вважаються перевіреними винятками"
Барт ван Хекелом

74
  1. Чи зазначене вище вважається перевіреним винятком? Ні Той факт, що ви обробляєте виняток, не робить його справжнім, Checked Exceptionякщо воно є RuntimeException.

  2. Є ? ТакRuntimeExceptionunchecked exception

Checked Exceptionsє subclassesв java.lang.Exception Unchecked Exceptionsце subclassesзjava.lang.RuntimeException

Виклики, що викидають перевірені винятки, повинні бути укладені у блок try {} або оброблятися на рівні вище у виклику методу. У цьому випадку поточний метод повинен оголосити, що він викидає зазначені винятки, щоб абоненти могли домовитись про відповідні винятки.

Сподіваюсь, це допомагає.

Питання: чи слід міхувати точний виняток або маскувати його за допомогою винятку?

Відповідь: Так, це дуже гарне питання та важливий розгляд дизайну. Клас Виняток - це дуже загальний клас винятків, який може використовуватися для внутрішнього виключення з низьким рівнем. Ви краще створіть спеціальний виняток і загорніть його всередину. Але, і велике - ніколи не було затьмарене в основі первинної першопричини. Наприклад, Don't everзробіть наступне -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Замість цього виконайте такі дії:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Виявлення оригінальних першопричинних поховань фактичною причиною після відновлення є кошмаром для виробничих груп підтримки, де до них надають доступ лише журнали програм та повідомлення про помилки. Хоча остання є кращою конструкцією, але багато людей не використовують її часто, оскільки розробники просто не передають основне повідомлення абоненту. Тож зробіть тверду зауваження: Always pass on the actual exceptionповертайтесь чи не в будь-яку програму, винятком якогось виключення.

На спробу лову RuntimeExceptions

RuntimeExceptions, як правило, не слід випробовувати. Зазвичай вони сигналізують про помилку програмування, і їх слід залишити в спокої. Натомість програміст повинен перевірити стан помилки, перш ніж викликати якийсь код, який може призвести до RuntimeException. Наприклад:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Це погана практика програмування. Натомість нульова перевірка повинна була бути виконана так:

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Але бувають випадки, коли така перевірка помилок дорога, наприклад, форматування чисел, врахуйте це -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

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

Отже, NullPointerExceptionі те і те NumberFormatExceptionі інше RuntimeExceptions, ловити a NullPointerExceptionслід замінити витонченою нульовою перевіркою, тоді як я рекомендую NumberFormatExceptionчітко вловлювати, щоб уникнути можливого введення коду, схильного до помилок.


Дякую. Ще одне запитання, коли ви перекидаєте exception, чи слід міхурувати точний виняток або маскувати його за допомогою Exception. Я пишу код поверх деякого застарілого коду, і Exceptionвін розповсюджується по всіх місцях. Цікаво, чи це правильна поведінка?
Тханг Фам

1
Це дуже хороше і важливе запитання, відредагувавши мою відповідь, щоб включити пояснення.
d-live

Дуже дякую. Чи можна було б вам показати мені зміст LoginFailureException(sqle)?
Тханг Фам

1
У мене немає жодного коду для цих речей, я просто підготував імена тощо. Якщо ви бачите java.lang.Exception, у нього є 4 конструктори, два з яких приймають java.lang.Throwable. У фрагментах вище я припускаю, що LoginFailureExceptionрозширює Exceptionта оголошує конструкторpublic LoginFailureException(Throwable cause) { super(cause) }
d-live

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

19

1. Якщо ви не знаєте про виняток, перевірте API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2. Так, і кожен виняток, який його поширює.

3. Не потрібно ловити та кидати той самий виняток. У цьому випадку можна показати новий діалоговий вікно файлів.

4. FileNotFoundException - це вже перевірений виняток.

5. Якщо очікується, що метод, що вимагає someMethodзловити виняток, останній може бути кинутий. Це просто "передає м'яч". Прикладом його використання може бути, якщо ви хочете перекинути його у власні приватні методи, а обробляти виняток у своєму публічному методі.

Гарне читання - сам документ Oracle: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

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

Наступне питання може бути таким: "Якщо так добре документувати API методу, включаючи винятки, які він може викинути, чому б не вказати також винятки з виконання часу?" Винятки під час виконання програми представляють проблеми, які є результатом проблеми програмування, і, таким чином, клієнтський код API не може обґрунтовано очікувати відновлення з них або будь-якого способу їх обробки. Такі проблеми включають арифметичні винятки, такі як ділення на нуль; винятки з вказівниками, такі як спроба отримати доступ до об'єкта через нульову посилання; та індексація винятків, наприклад, спроба отримати доступ до елемента масиву через занадто великий або занадто малий індекс.

Також у специфікації мови Java є важливий біт інформації :

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

Суть IMHO полягає в тому, що ви можете зловити будь-якого RuntimeException, але вас не вимагають, і насправді від виконання цього проекту не потрібно підтримувати ті самі неперевірені винятки, які викинуті, оскільки вони не є частиною договору.


Дякую. Ще одне запитання, коли ви перекидаєте exception, чи слід міхурувати точний виняток або маскувати його за допомогоюException . Я пишу код поверх деякого застарілого коду, і Exceptionвін розповсюджується по всіх місцях. Цікаво, чи це правильна поведінка?
Thang Pham

1
@ Харі, я дозволю людям, які мають більше знань, ніж я, щоб відповісти на це: stackoverflow.com/questions/409563/…
Aleadam

10

1) Ні, NumberFormatException - це неперевірений виняток. Навіть незважаючи на те, що ви його зловили (не вимагаєте), оскільки це не перевірено Це тому, що це підклас, IllegalArgumentExceptionякий є підкласом RuntimeException.

2) RuntimeExceptionє коренем усіх неперевірених Винятків. Кожний підклас RuntimeExceptionвідсутній. Усі інші винятки і Throwableперевіряються, за винятком помилок (що підпадає під Throwable).

3/4) Ви можете попередити користувача, що він вибрав неіснуючий файл і попросити новий. Або просто киньте повідомляти користувача, що він ввів щось недійсне.

5) Кидати і ловити 'Exception'- це погана практика. Але загалом, ви можете кинути інші винятки, щоб абонент міг вирішити, як з цим боротися. Наприклад, якщо ви написали бібліотеку для читання деякого введення файлу, і ваш метод був переданий неіснуючим файлом, ви не знаєте, як з цим впоратися. Чи хоче абонент знову запитати чи кинути? Таким чином, ви кидаєте Виняток вгору по ланцюгу назад до абонента.

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


Дякую. Ще одне запитання, коли ви перекидаєте exception, чи слід міхурувати точний виняток або маскувати його за допомогоюException . Я пишу код поверх деякого застарілого коду, і Exceptionвін розповсюджується по всіх місцях. Цікаво, чи це правильна поведінка?
Thang Pham

Ви можете просто так, щоб ваш метод також кинув виняток (що не ідеально). Або зловити виняток і кинути кращий виняток (наприклад, IOException чи щось таке). Усі винятки можуть сприймати виняток у своєму конструкторі як «причину», тому вам слід скористатися цим.
dontocsata

8

Перевірено - Схильне відбуватися. Перевірено в час компіляції.

Напр. Файлові операції

Не перевірено - Через неправильні дані. Перевірено під час виконання.

Наприклад

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Тут виняток пов’язаний з поганими даними, і жодним чином їх неможливо визначити під час компіляції.


6

Перевірені винятки перевіряються в момент компіляції JVM та пов'язані з ними ресурси (файли / db / stream / socket тощо). Мотив перевіреного винятку полягає в тому, що під час компіляції, якщо ресурси недоступні, додаток повинен визначити альтернативну поведінку для вирішення цього питання в блоці catch / нарешті.

Неперевірені винятки - це суто програмні помилки, неправильний розрахунок, нульові дані або навіть збої в бізнес-логіці можуть призвести до винятку з виконання. Це абсолютно добре для обробки / вилучення неперевірених винятків у коді.

Пояснення, взяті з http://coder2design.com/java-interview-questions/


5

Моя абсолютна улюблена характеристика різниці між неперевіреними та перевіреними винятками надана статтею з навчального посібника Java " Неперевірені винятки - суперечка " (вибачте, що ви можете отримати все елементарне в цій публікації - але, ей, основи часом найкращі):

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

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

Потім решта стає логічною: на які винятки компілятор очікує, що я відповім явно? Ті, від яких ви очікуєте відновлення клієнта.


5

Щоб відповісти на остаточне запитання (інші, здається, ґрунтовно відповіли вище), "Чи слід міхувати точний виняток або замаскувати його за допомогою Exception?"

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

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Ні, завжди оголошуйте найточніший можливий виняток або перелік таких. Винятки, які ви заявляєте, що ваш метод є здатним кинути, є частиною договору між вашим методом та абонентом. Кидання "FileNotFoundException"означає, що можливо ім'я файлу недійсне і файл не буде знайдений; абоненту потрібно буде з цим розумно поводитися. Кидати Exceptionозначає "Гей, трапляється. Діла". Що дуже бідно API.

У коментарях до першої статті є кілька прикладів, коли "кидки Exception" є дійсною та обґрунтованою декларацією, але це не стосується більшості normalкодів, які ви коли-небудь пишете "".


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

5

Винятки під час виконання : Винятки під час виконання позначаються як неперевірені винятки. Усі інші винятки - це перевірені винятки, і вони не походять від java.lang.RuntimeException.

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

Ряд методів Java API кидає перевірені винятки, тому ви часто пишете обробники винятків, щоб справлятися з винятками, створеними методами, які ви не писали.


3

Чому вони пускають виняток на пульс? Чи не краще поправити помилку раніше? Чому бульбашки?

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

Примітка. Щоб дати чітку характеристику того, який тип помилки стався, ми можемо створити власний об’єкт «Виняток» та передати його клієнту.


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

3

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

Докладніше про перевірені та неперевірені винятки читайте тут http://learnjava.today/2015/11/ checked-vs-uncont-exceptions/


3

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

Щоразу, коли є включені перевірені винятки, throws CheckedExceptionдесь є підпис методу ( CheckedExceptionможе бути будь-який перевірений виняток). Підпис НЕ кидає виняток, кидання винятків є аспектом реалізації. Інтерфейси, підписи методів, батьківські класи, всі ці речі НЕ повинні залежати від їх реалізації. Використання тут перевірених винятків (фактично той факт, що вам потрібно оголосити throwsв підписі методу) пов'язує ваші інтерфейси вищого рівня з вашими реалізаціями цих інтерфейсів.

Дозвольте показати вам приклад.

Давайте мати такий гарний та чистий інтерфейс, як цей

public interface IFoo {
    public void foo();
}

Тепер ми можемо написати багато реалізацій методу foo(), як ці

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Class Foo - це прекрасно. Тепер давайте зробимо першу спробу в класі Bar

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Бар цього класу не збирається. Оскільки InterruptException є перевіреним винятком, ви повинні або захопити його (з пробним уловом всередині методу foo ()), або заявити, що ви його кидаєте (додавши throws InterruptedExceptionдо підпису методу). Оскільки я не хочу зафіксувати цей виняток тут (я хочу, щоб воно поширювалося вгору, щоб я міг належним чином впоратися з ним деінде), давайте змінимо підпис.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Цей бар-клас також не буде компілюватися! Метод Bar foo () НЕ перекриває метод IFoo foo (), оскільки їх підписи різні. Я міг би видалити анотацію @Override, але я хочу програмувати на інтерфейс IFoo, як, IFoo foo;і пізніше вирішити, яку реалізацію я хочу використовувати, як foo = new Bar();. Якщо метод Bar foo () не перекриває метод foo IFoo, коли я foo.foo();це робити, він не закликає реалізацію Bar foo ().

Щоб public void foo() throws InterruptedExceptionперемогти Bar у IFoo, public void foo()Я ОБОВ'ЯЗКОВО додати throws InterruptedExceptionпідпис методу IFoo. Однак це спричинить проблеми з моїм класом Foo, оскільки підпис методу foo () відрізняється від підпису методу IFoo. Крім того, якби я додавав throws InterruptedExceptionдо методу Foo (foo (), я отримав би ще одну помилку, вказуючи, що метод Foo foo () заявляє, що він кидає InterruptException, але він ніколи не кидає InterruptException.

Як ви бачите (якщо я зробив гідну роботу з поясненням цього матеріалу), той факт, що я кидаю перевірений виняток, такий як InterruptException, змушує мене прив'язати інтерфейс IFoo до однієї з його реалізації, що, в свою чергу, спричиняє хаос у IFoo інші реалізації!

Це одна велика причина, чому перевірені винятки - BAD. У шапках.

Одне рішення - захопити перевірений виняток, загорнути його у неперевірений виняток та викинути неперевірене виключення.


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

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

"Однак це спричинить проблеми з моїм класом Foo, оскільки підпис методу foo () відрізняється від підпису методу IFoo". Я щойно перевірив вашу ідею, і її можна скласти, навіть якщо ми додамо throws InterruptedExceptionдо підпису методу IFoo, не кидаючи нічого в жодну реалізацію. Тож це насправді не викликає жодних проблем. Якщо в інтерфейсі ви робите кожен метод кидання підписів Exception, він просто надає реалізації вибір викинути або не викинути виняток (будь-який виняток, оскільки Exceptionінкапсулює всі винятки).
Flyout91

Однак я визнаю, що це може бути заплутано, оскільки коли ви реалізуєте такий інтерфейс і натисніть на щось на кшталт "Додати непроведені методи", вони будуть автоматично створені за допомогою throw Exceptionпідпису в їх підписі, навіть якщо ваша реалізація нічого не кине або може бути більш конкретний виняток. Але я все ще відчуваю, що це хороша практика завжди кидати виняток за метод інтерфейсу, оскільки, знову ж таки, це дає користувачеві можливість викидати чи не кидати щось.
Flyout91

Тут пропускається вся точка. Мета інтерфейсу - оголосити контракт, який вимагає виконання клієнтом. Сюди можна віднести сценарії відмов, з якими вона здатна впоратися. Коли реалізація стикається з помилкою, вона повинна відображати цю помилку на відповідний абстрактний збій, оголошений клієнтським інтерфейсом.
erickson

3
  • Java розрізняє дві категорії винятків (перевірено та невірно).
  • Java застосовує вимогу щодо вилову або заявленої вимоги для перевірених винятків.
  • Тип винятку визначає, перевіряється чи не перевіряється виняток.
  • Усі типи винятків, які є прямими або непрямими subclassesдля класу, RuntimeException є неперевіреними винятками.
  • Усі класи, які успадковуються від класу, Exceptionале не RuntimeExceptionвважаються такими checked exceptions.
  • Класи, які успадковують від класу Помилка, вважаються невизначеними.
  • Компілятор перевіряє кожен виклик методу і уповільнення, щоб визначити, чи кидає метод checked exception.
    • Якщо так, компілятор гарантує, що виняток буде схоплено або оголошено у закиданні.
  • Щоб задовольнити заявлену частину вимоги "приховати або оголосити", метод, що генерує виняток, повинен передбачати throwsпункт, що містить checked-exception.
  • Exception класи визначаються для перевірки, коли вони вважаються досить важливими, щоб зловити або оголосити.

2

Ось просте правило, яке може допомогти вам визначитися. Це пов'язано з тим, як інтерфейси використовуються в Java.

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

Подивіться на методи інтерфейсу та розгляньте винятки, які вони можуть кинути:

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

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

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

Зазвичай ви не плануєте «вибухувати» винятки (ловити та перекидати). Або виняток повинен обробляти абонент (у такому випадку він перевіряється) або він повинен пройти весь шлях до обробника високого рівня (у такому випадку це найпростіше, якщо це не встановлено).


2

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


2

Коротше кажучи, винятки, якими повинен працювати ваш модуль або модулі під час виконання, називаються перевіреними винятками; інші - це неперевірені винятки, які є RuntimeExceptionабо Error.

У цьому відео вона пояснює перевірені та неперевірені винятки на Java:
https://www.youtube.com/watch?v=ue2pOqLaArw


1

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


гм якщо NumberFormatException є перевіреним винятком, як ви кажете, чи не суперечить він тому, що він успадковується від RuntimeException ?
ей

Вибачте, я був не дуже зрозумілий. Я мав на увазі FileNotFoundException, а не NumberFormatException. Виходячи з його №2 і №4, здавалося, він вважав, що "Перевірено проти Не перевірено" базується на тому, як ви обробляєте виняток після його лову. Не так, як це було визначено.
мамбокінг

-1

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

"Хоча це перевірене виняток, воно рідко піддається відшкодуванню. Більшість абонентів повинні просто загорнути цей виняток у неперевірений виняток та повторно скинути:"

То чому б у світі хтось змусив розробників продовжувати перевіряти виняток, якщо нам слід «просто обернути його»? Лол

http://developer.android.com/reference/org/json/JSONException.html


4
Оскільки лише більшість абонентів, а не всі, хто телефонує, повинні обгортати та повторювати. Той факт, що виняток перевіряється, означає, що абонент повинен задуматися, чи є вони одним із "найбільш" абонентів, або одним із меншин, який може і повинен обробляти виняток.
Warren Dew

1
Якщо вам подобається перевіряти помилки під час кожного дзвінка, "поверніться" до C. Винятки - це спосіб відокремити звичайне виконання програми від ненормального, не забруднюючи код. Винятки гарантують, що ви не можете мовчки ігнорувати помилку на якомусь рівні .
Славомир

-1

Перевірені винятки :

  • Винятки, які перевіряє компілятор на плавне виконання програми під час виконання, називаються перевіреними винятками.

  • Вони відбуваються під час компіляції.

  • Якщо вони не оброблені належним чином, вони дадуть помилку часу компіляції (не виняток).
  • Усі підкласи класу винятку, крім RuntimeException, є перевіреними винятками.

    Гіпотетичний приклад - припустимо, ви виходите з дому для іспиту, але якщо ви перевірите, чи брали ви свій заліковий квиток вдома (час складання), то в залі залі (час виконання) не виникне жодних проблем.

Неперевірене виняток :

  • Винятки, які не перевіряється компілятором, називаються Неперевіреними винятками.

  • Вони трапляються під час виконання.

  • Якщо ці винятки не обробляються належним чином, вони не дають помилки часу компіляції. Але програма буде припинена передчасно під час виконання.

  • Усі підкласи RunTimeException та Error є виключеними винятками.

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


-2

Усі винятки повинні бути перевірені винятками.

  1. Неперевірені винятки - це необмежені готи. А необмежений готос вважається поганою справою.

  2. Неперевірені винятки порушують інкапсуляцію. Щоб правильно їх обробити, необхідно знати всі функції в дереві викликів між метальником і ловом, щоб уникнути помилок.

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

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