Як боротися з перевіреними винятками, які ніколи не можна кинути


35

Приклад:

foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");

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

Наразі це виглядає так

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
}
catch(UnsupportedEncodingException e) { /* won't ever happen */ }

Будь-які ідеї, як зробити це краще?


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

1
`киньте новий ImpossibleException (" Перезавантажте Всесвіт. Речі переплутані ", е);
Кріс Кадмор

1
"Ніколи не трапиться" стане ...

Thorbjørn Ravn Andersen: це може змінити програму, але принаймні в її нинішньому стані жоден набір вхідних даних не може викликати виняток.
користувач281377

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

Відповіді:


27

Моя звичка - просто бути в безпечній стороні, щоб вкласти assertв блок ловлі. Хтось може змінити вміст tryблоку пізніше, і ви хочете знати, чи не виходить код, чи не так?


Гарна ідея; простий assert false;не додає занадто великої безладу і дає зрозуміти, що я припускаю, що блок ловлі ніколи не буде введений.
користувач281377

5
@ammoQ, або ви навіть можете додати повідомлення , щоб зробити ваше намір абсолютно ясно: assert false : "should never happen".
Péter Török

13
Ще краще, "Ніколи не ставатиме тому, що Java вимагає підтримувати схему ISO-8859-1".
дан04

3
assertозначає, що твердження увімкнено. Я кидаю UnexpectedException(що також має перевагу, якщо я маю стек стека ...).
Чоп

35

Якби мені давали цент за кожен раз, коли я бачив журнал / помилку, "Це ніколи не повинно трапитися", я мав би ... ну, два центи. Але все ж...

Порожні блоки вилову змушують мої павукоподібні відчуття поколюватися, і більшість хороших інструментів аналізатора коду скаржаться. Я б уникнув за будь-яку ціну залишити їх порожніми. Звичайно, тепер ви знаєте, що помилка ніколи не може трапитися, але через рік хтось зробить глобальний пошук-заміну «ISO-8859-1», і раптом у вас може виявитися вкрай важко знайти помилку.

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


28

Я завжди робив це так:

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
} catch(UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

Може бути дещо багатослівним (Java - це ...), але принаймні ви отримаєте помилку твердження, коли станеться неможливе.

Якщо реалізація Java порушена, вам потрібно буде якомога швидше отримати якомога краще повідомлення про помилку, а не просто ігнорувати неможливе. І навіть якщо реалізація Java не порушена, хтось міг змінити ваш код на "UTF8"(ой, чи мав би бути "UTF-8"?).

Це, в першу чергу, повинно було бути виключенням для виконання. JDK сповнений такого роду неправильного вибору.


4
Справжнє неправильне рішення (або упущення, якщо ви хочете) полягає в тому, що для цих 6 символів, які потрібні Java, немає заздалегідь визначених екземплярів Charset. foobar = new InputStreamReader(p.getInputStream(), Charset.ISO_8859_1);- Невже зараз це не буде приємніше і уникати будь-якої помилки раз і назавжди?
користувач281377

3
У бібліотеці Гуави є багато цих речей. Полегшує життя.

3
У Java 1.7+ встановлені константи шаблонів : docs.oracle.com/javase/7/docs/api/java/nio/charset/… . Використовуйте їх так: StandardCharsets.UTF_8.displayName ()
Майкл

4

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


4

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

Коли я нав'язливий щодо висвітлення, я згорню спробу / зловити, що "ніколи не може відбутися" (... або лише якщо я використовую мутантний JVM, який якось забув включити "US-ASCII") у клас та метод, який інкапсулює спробу / ловити, та замінить перевірений виняток одним із способів, згаданих тут (як правило, викидання неперевіреного винятку повідомленням із сніда).

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

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

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

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