TL; DR
Приміщення
- Винятки з виконання повинні бути викинуті, коли помилка не виправляється: коли помилка знаходиться в коді, і не залежить від зовнішнього стану (таким чином, відновлення буде виправляти код).
- Перевірені винятки слід скидати, коли код правильний, але зовнішній стан не такий, як очікувалося: відсутність підключення до мережі, файл не знайдений або пошкоджений тощо.
Висновок
Ми можемо повторно скинути перевірений виняток як виняток під час виконання, якщо розповсюджуючий чи інтерфейсний код припускає, що базове виконання залежить від зовнішнього стану, коли цього явно немає.
У цьому розділі йдеться про те, коли потрібно кинути будь-який з винятків. Ви можете перейти до наступної горизонтальної смуги, якщо ви просто хочете прочитати більш детальне пояснення для висновку.
Коли доцільно кинути виняток із виконання? Ви викидаєте виняток із виконання, коли зрозуміло, що код неправильний, і що відновлення доцільно, змінивши код.
Наприклад, доцільно кинути виняток з виконання для наступного:
float nan = 1/0;
Це викине поділ за нульовим винятком виконання. Це доречно, оскільки код несправний.
Або, наприклад, ось частина конструктора HashMap
's:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// more irrelevant code...
}
Щоб виправити початкову потужність або коефіцієнт завантаження, доречно, щоб ви відредагували код, щоб переконатися, що правильні значення передаються. Це не залежить від того, який сервер знаходиться далеко, від поточного стану диска, файл або інша програма. Цей конструктор, який викликається недійсними аргументами, залежить від правильності виклику коду, будь то неправильний розрахунок, який призвів до недійсних параметрів або невідповідного потоку, який пропустив помилку.
Коли доцільно кинути перевірений виняток? Ви кидаєте перевіряється виключення , коли питання є очікуваного відшкодування без зміни коду. Або, якщо говорити це по-різному, ви кидаєте перевірений виняток, коли помилка пов'язана зі станом, а код правильний.
Тепер слово "відновити" може бути тут складним. Це може означати, що ви знайдете інший спосіб досягти мети: Наприклад, якщо сервер не відповідає, то слід спробувати наступний сервер. Якщо такий спосіб відновлення можливий у вашому випадку, то це чудово, але це не єдине, що означає відновлення - відновлення може просто відображати користувачеві діалог помилок, який пояснює, що сталося, або якщо це серверне додаток, то це може бути надсилання електронного листа адміністратору або навіть просто реєстрація помилки належним чином і стисло.
Візьмемо приклад, який згадувався у відповіді mrmuggles:
public void dataAccessCode(){
try{
..some code that throws SQLException
}catch(SQLException ex){
throw new RuntimeException(ex);
}
}
Це не правильний спосіб поводження з перевіреним винятком. Сама нездатність обробляти виняток із сфери застосування цього методу не означає, що додаток має бути збій. Замість цього доцільно поширити його на більш високу сферу, наприклад:
public Data dataAccessCode() throws SQLException {
// some code that communicates with the database
}
Що дозволяє можливість відновлення абонентом:
public void loadDataAndShowUi() {
try {
Data data = dataAccessCode();
showUiForData(data);
} catch(SQLException e) {
// Recover by showing an error alert dialog
showCantLoadDataErrorDialog();
}
}
Перевірені винятки є інструментом статичного аналізу, вони дають зрозуміти програмісту, що може піти не так у певному виклику, не вимагаючи від них вивчити реалізацію або пройти процес проб та помилок. Це дозволяє легко переконатися, що жодна частина потоку помилок не буде ігнорована. Перевизначення перевіреного винятку як винятку під час виконання працює проти цієї функції статичного аналізу економії праці.
Варто також зазначити, що викликовий шар має кращий контекст грандіознішої схеми речей, як було показано вище. Причин, за якими dataAccessCode
можна було б викликати, може бути багато , конкретна причина виклику видна лише абоненту - таким чином він може прийняти краще рішення при правильному відновленні після відмови.
Тепер, коли ми зрозуміли це розрізнення, ми можемо перейти до виведення, коли нормально повторно скинути перевірений виняток як виняток із виконання.
З огляду на вищесказане, коли доцільно повторно скинути перевірений виняток як RuntimeException? Коли використовуваний вами код передбачає залежність від зовнішнього стану, але ви можете чітко стверджувати, що він не залежить від зовнішнього стану.
Розглянемо наступне:
StringReader sr = new StringReader("{\"test\":\"test\"}");
try {
doesSomethingWithReader(sr); // calls #read, so propagates IOException
} catch (IOException e) {
throw new IllegalStateException(e);
}
У цьому прикладі код поширюється, IOException
оскільки API Reader
розроблений для доступу до зовнішнього стану, проте ми знаємо, що StringReader
реалізація не має доступу до зовнішнього стану. У цій галузі, де ми можемо, безумовно, стверджувати, що частини, що беруть участь у виклику, не мають доступу до IO або будь-якого іншого зовнішнього стану, ми можемо сміливо переосмислити виняток як виняток під час виконання, не дивуючи колег, які не знають про нашу реалізацію (і можливо припускаючи, що код, що має доступ до IO, буде кидати an IOException
).
Причиною суворого контролю винятків , що залежать від зовнішнього стану, є те, що вони є недетермінованими (на відміну від винятків, залежних від логіки, які передбачувано відтворюватимуться кожного разу для версії коду). Наприклад, якщо ви спробуєте поділити на 0, ви завжди створюватимете виняток. Якщо ви не розділите на 0, ви ніколи не створите винятку, і вам не доведеться обробляти цей виняток, тому що він ніколи не відбудеться. У випадку доступу до файлу, однак один раз успіх не означає, що наступного разу ви досягнете успіху - користувач, можливо, змінив дозволи, інший процес може видалити або змінити його. Тому вам завжди доводиться працювати з цим винятковим випадком, або у вас, ймовірно, є помилка.