Відповіді:
Взагалі ніколи.
Однак іноді потрібно ловити конкретні помилки.
Якщо ви пишете фреймворк-код (завантаження сторонніх класів), це може бути розумно зловити LinkageError
(не знайдено визначення класу, незадовільне посилання, несумісні зміни класу).
Я також бачив якийсь нерозумний сторонній код, який кидає підкласи Error
, тому вам доведеться також і з ними.
До речі, я не впевнений, що від цього неможливо відновитись OutOfMemoryError
.
Ніколи. Ви ніколи не можете бути впевнені, що програма зможе виконати наступний рядок коду. Якщо ви отримаєте OutOfMemoryError
, у вас немає гарантії, що ви зможете зробити щось надійно . Ловіть RuntimeException і перевіряйте винятки, але ніколи не помилки.
boolean assertionsEnabled = false; assert assertionsEnabled = true;
Як правило, ви завжди повинні їх ловити java.lang.Error
та записувати до журналу або демонструвати користувачеві. Я працюю в підтримку і щодня бачу, що програмісти не можуть розповісти, що сталося в програмі.
Якщо у вас є демонова нитка, ви повинні запобігти її припиненню. В інших випадках ваша програма працюватиме коректно.
Ви повинні ловити лише java.lang.Error
на найвищому рівні.
Якщо ви подивитесь на список помилок, ви побачите, що більшість з них можна впоратися. Наприклад, ZipError
виникає при читанні пошкоджених поштових файлів.
Найбільш поширені помилки - це, OutOfMemoryError
і NoClassDefFoundError
вони в більшості випадків є проблемами виконання.
Наприклад:
int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];
може спричинити, OutOfMemoryError
але це проблема часу виконання і немає причин припиняти програму.
NoClassDefFoundError
виникають здебільшого, якщо бібліотеки немає або якщо ви працюєте з іншою версією Java. Якщо це додаткова частина вашої програми, ви не повинні припиняти програму.
Я можу навести ще багато прикладів того, чому це гарна ідея піти Throwable
на найвищому рівні та створити корисне повідомлення про помилку.
OutOfMemoryError
не є помилкою виконання, немає гарантії, що програма може відновитись із неї. Якщо вам пощастить, ви можете отримати OOM, new byte[largeNumber]
але якщо цього виділення було недостатньо, щоб викликати OOM, це може бути запущено в наступному рядку або наступному потоці. Це проблема часу виконання, оскільки, якщо length
вхід недовірений, його слід перевірити перед викликом new byte[]
.
NoClassDefFoundError
може виникати де завгодно , оскільки він викликається, коли компільований код Java не може знайти клас. Якщо ваш JDK неправильно налаштований, це може спричинити спробу використання java.util.*
класу, і програмувати його практично неможливо. Якщо ви необов'язково включаєте залежність, вам слід скористатися, ClassLoader
щоб перевірити, чи існує вона, яка кидає ClassNotFoundException
.
ZipError
вказує, що файл jar, що містить класи, є пошкодженим zip-файлом. Це досить серйозна проблема, і на даний момент ви не можете довіряти жодному коду, який буде виконуватися, і це було б безвідповідально за спробу "відновити" з нього.
java.lang.Error
або java.lang.Throwable
на найвищому рівні і спробувати щось зробити з цим - скажімо, запишіть повідомлення про помилку. Але на той момент немає гарантії, що це буде виконано. Якщо ваш JVM є OOMing, спроба входу може виділити більше String
s, що запускає іншу OOM.
У багатопотоковому середовищі ви найчастіше хочете його зловити! Коли ви його впіймаєте, запишіть його та закрийте всю програму! Якщо цього не зробити, якась нитка, яка може зробити якусь важливу частину, буде мертвою, а решта програми вважатиме, що все нормально. З цього може трапитися багато небажаних ситуацій. Одна з найменших проблем полягає в тому, що ви не зможете легко знайти корінь проблеми, якщо інші потоки почнуть викидати деякі винятки через те, що одна нитка не працює.
Наприклад, зазвичай цикл повинен бути:
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
Навіть у деяких випадках ви хочете по-різному обробляти різні помилки, наприклад, на OutOfMemoryError ви зможете регулярно закривати додаток (навіть, можливо, звільнити деяку пам’ять і продовжувати), а в деяких інших - зробити це не так вже й багато.
OutOfMemoryError
та продовжувати, а не існувати негайно, нерозумно, оскільки ваша програма перебуває у невизначеному стані .
Error
Зазвичай не повинні бути спіймані , оскільки це вказує на ненормальний стан , який ніколи не повинен статися .
З специфікації Java API для Error
класу:
Це
Error
підклас,Throwable
який вказує на серйозні проблеми, які розумне застосування не повинно намагатися наздогнати. Більшість таких помилок - це ненормальні умови. [...]Метод не зобов’язаний оголошувати в пункті кидок будь-які підкласи помилки, які можуть бути кинуті під час виконання методу, але не виявлені, оскільки ці помилки - це аномальні умови, які ніколи не повинні виникати.
Як зазначається в специфікації, анкета Error
кидається лише в обставинах, які є, Швидше за все, якщо програма Error
трапляється, програма може зробити дуже мало, а в деяких випадках сама віртуальна машина Java може перебувати в нестабільному стані (наприклад, VirtualMachineError
)
Хоча an Error
є підкласом, Throwable
що означає, що він може бути зафіксований try-catch
пунктом, але він, ймовірно, насправді не потрібен, оскільки додаток буде в ненормальному стані, коли Error
кидок буде переданий JVM.
Там також короткий розділ по цій темі в розділі 11.5 Ієрархія винятків з специфікації мови Java, 2nd Edition .
І є кілька інших випадків, коли якщо ви потрапили на помилку, вам доведеться її повторно скинути . Наприклад, ThreadDeath ніколи не повинен бути спійманий, це може спричинити велику проблему, якщо ви його зловите в умовах, що міститься (наприклад, сервер програми):
Додаток має фіксувати екземпляри цього класу лише у тому випадку, якщо він повинен очиститися після припинення асинхронно. Якщо ThreadDeath потрапляє методом, важливо, щоб він був перетоплений, щоб нитка насправді відмирала.
Error
s.
Дуже, дуже рідко.
Я робив це лише для одного дуже конкретного відомого випадку. Наприклад, java.lang.UnsatisfiedLinkError може бути кинутим, якщо два незалежність ClassLoader завантажують ту саму DLL. (Я згоден, що я повинен перемістити JAR до спільного завантажувача класів)
Але найпоширеніший випадок - це те, що вам потрібен був журнал, щоб знати, що сталося, коли користувач прийшов скаржитися. Ви хочете, щоб повідомлення або спливаюче вікно для користувача, а не мовчки мертві.
Навіть програміст на C / C ++, вони виявляють помилку і повідомляють те, що люди не розуміють, перш ніж вона вийде (наприклад, поломка пам'яті).
У додатку для Android я ловлю java.lang.VerifyError . Бібліотека, яку я використовую, не працюватиме на пристроях зі старою версією ОС, і код бібліотеки видасть таку помилку. Я, звичайно, міг уникнути помилки, перевіривши версію ОС під час виконання, але:
В ідеалі ми не повинні обробляти / вловлювати помилки. Але можуть бути випадки, коли нам це потрібно робити, виходячи з вимог рамки чи застосування. Скажімо, у мене демон XML Parser, який реалізує DOM Parser, який споживає більше пам'яті. Якщо є така вимога, як нитка Parser, не слід загинути, коли вона отримує OutOfMemoryError , замість цього вона повинна обробляти її та надсилати повідомлення / пошту адміністратору програми / фреймворку.
Виникла помилка, коли JVM більше не працює, як очікувалося, або стоїть на межі. Якщо ви вводите помилку, немає гарантії, що блок лову буде працювати, і тим більше, що він буде працювати до кінця.
Це також залежатиме від працюючого комп'ютера, поточного стану пам’яті, тому немає можливості перевірити, спробувати і зробити все можливе. У вас буде тільки шалений результат.
Ви також зменшите читабельність свого коду.