Коли ловити java.lang.Error?


Відповіді:


101

Взагалі ніколи.

Однак іноді потрібно ловити конкретні помилки.

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

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

До речі, я не впевнений, що від цього неможливо відновитись OutOfMemoryError.


3
Що мені довелося зробити саме для завантаження DLL, це вийде з ладу, якщо вони не були правильно налаштовані. Не фатальна помилка у випадку цієї програми.
Mario Ortegón

7
Іноді має сенс ловити OutOfMemoryError - наприклад, коли ви створюєте великі списки масивів.
SpaceTrucker

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

@PJTraill Я не впевнений у цьому. Для цього знадобляться статистичні вибірки реального світу. Я думав, що бачив такий код, але не можу пригадати, де він був.
SpaceTrucker

51

Ніколи. Ви ніколи не можете бути впевнені, що програма зможе виконати наступний рядок коду. Якщо ви отримаєте OutOfMemoryError, у вас немає гарантії, що ви зможете зробити щось надійно . Ловіть RuntimeException і перевіряйте винятки, але ніколи не помилки.

http://pmd.sourceforge.net/rules/strictexception.html


27
Ніколи не кажи ніколи. у нас є код тестування, який робить "стверджувати помилковим"; потім ловить AssertionError, щоб переконатися, що встановлено прапор -ea. Окрім цього ... так, напевно, ніколи ;-)
Програматор поза законом

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

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

Як щодо помилок, наприклад, NoSuchMethodError, що надходить від сторонніх методів бібліотеки?
ha9u63ar

@OutlawProgrammer Тільки для запису, є й інші способи зробити той самий тест:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel

16

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

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

Ви повинні ловити лише java.lang.Errorна найвищому рівні.

Якщо ви подивитесь на список помилок, ви побачите, що більшість з них можна впоратися. Наприклад, ZipErrorвиникає при читанні пошкоджених поштових файлів.

Найбільш поширені помилки - це, OutOfMemoryErrorі NoClassDefFoundErrorвони в більшості випадків є проблемами виконання.

Наприклад:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

може спричинити, OutOfMemoryErrorале це проблема часу виконання і немає причин припиняти програму.

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

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


Я б підозрював, що в тих випадках краще провалити демон з належними сповіщеннями, щоб мати можливість залишатися в живих як якийсь ефірний привид на невдалому jvm, де це може дати помилковий привід, що він дійсно живий і щось робить
Ендрю Норман

OutOfMemoryErrorне є помилкою виконання, немає гарантії, що програма може відновитись із неї. Якщо вам пощастить, ви можете отримати OOM, new byte[largeNumber]але якщо цього виділення було недостатньо, щоб викликати OOM, це може бути запущено в наступному рядку або наступному потоці. Це проблема часу виконання, оскільки, якщо lengthвхід недовірений, його слід перевірити перед викликом new byte[].
Jeeyoung Kim

NoClassDefFoundErrorможе виникати де завгодно , оскільки він викликається, коли компільований код Java не може знайти клас. Якщо ваш JDK неправильно налаштований, це може спричинити спробу використання java.util.*класу, і програмувати його практично неможливо. Якщо ви необов'язково включаєте залежність, вам слід скористатися, ClassLoaderщоб перевірити, чи існує вона, яка кидає ClassNotFoundException.
Jeeyoung Kim

1
ZipErrorвказує, що файл jar, що містить класи, є пошкодженим zip-файлом. Це досить серйозна проблема, і на даний момент ви не можете довіряти жодному коду, який буде виконуватися, і це було б безвідповідально за спробу "відновити" з нього.
Jeeyoung Kim

2
Взагалі, це може бути корисно зловити java.lang.Errorабо java.lang.Throwableна найвищому рівні і спробувати щось зробити з цим - скажімо, запишіть повідомлення про помилку. Але на той момент немає гарантії, що це буде виконано. Якщо ваш JVM є OOMing, спроба входу може виділити більше Strings, що запускає іншу OOM.
Jeeyoung Kim

15

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

Наприклад, зазвичай цикл повинен бути:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

Навіть у деяких випадках ви хочете по-різному обробляти різні помилки, наприклад, на OutOfMemoryError ви зможете регулярно закривати додаток (навіть, можливо, звільнити деяку пам’ять і продовжувати), а в деяких інших - зробити це не так вже й багато.


1
Ловити OutOfMemoryError та продовжувати, а не існувати негайно, нерозумно, оскільки ваша програма перебуває у невизначеному стані .
Raedwald

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

9

Дуже рідко.

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

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


6

Майже ніколи. Помилки створені як проблеми, з якими програми зазвичай нічого не можуть зробити. Єдиним винятком може слугувати подання помилки, але навіть це може бути не так, як планувалося залежно від помилки.


6

ErrorЗазвичай не повинні бути спіймані , оскільки це вказує на ненормальний стан , який ніколи не повинен статися .

З специфікації Java API для Errorкласу:

Це Errorпідклас, Throwable який вказує на серйозні проблеми, які розумне застосування не повинно намагатися наздогнати. Більшість таких помилок - це ненормальні умови. [...]

Метод не зобов’язаний оголошувати в пункті кидок будь-які підкласи помилки, які можуть бути кинуті під час виконання методу, але не виявлені, оскільки ці помилки - це аномальні умови, які ніколи не повинні виникати.

Як зазначається в специфікації, анкета Errorкидається лише в обставинах, які є, Швидше за все, якщо програма Errorтрапляється, програма може зробити дуже мало, а в деяких випадках сама віртуальна машина Java може перебувати в нестабільному стані (наприклад, VirtualMachineError)

Хоча an Errorє підкласом, Throwableщо означає, що він може бути зафіксований try-catchпунктом, але він, ймовірно, насправді не потрібен, оскільки додаток буде в ненормальному стані, коли Errorкидок буде переданий JVM.

Там також короткий розділ по цій темі в розділі 11.5 Ієрархія винятків з специфікації мови Java, 2nd Edition .


6

Якщо ви досить божевільні, щоб створити нову рамку тестування модуля, ваш тестовий бігун, ймовірно, повинен буде зловити java.lang.AssertionError, кинутий будь-якими тестовими кейсами.

В іншому випадку дивіться інші відповіді.


5

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

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


2
Що насправді не випуск, тому що ви просто не ловите Errors.
Бомбе

4

Дуже, дуже рідко.

Я робив це лише для одного дуже конкретного відомого випадку. Наприклад, java.lang.UnsatisfiedLinkError може бути кинутим, якщо два незалежність ClassLoader завантажують ту саму DLL. (Я згоден, що я повинен перемістити JAR до спільного завантажувача класів)

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

Навіть програміст на C / C ++, вони виявляють помилку і повідомляють те, що люди не розуміють, перш ніж вона вийде (наприклад, поломка пам'яті).


3

У додатку для Android я ловлю java.lang.VerifyError . Бібліотека, яку я використовую, не працюватиме на пристроях зі старою версією ОС, і код бібліотеки видасть таку помилку. Я, звичайно, міг уникнути помилки, перевіривши версію ОС під час виконання, але:

  • Найстаріший підтримуваний SDK може змінитися в майбутньому для конкретної бібліотеки
  • Блок помилок спроб уловлювання є частиною більшого механізму відхилення. Деякі конкретні пристрої, хоча вони мають підтримувати бібліотеку, викидають винятки. Я ловлю VerifyError та всі винятки, щоб використовувати рішення із зворотного зв'язку.

3

досить зручно ловити java.lang.AssertionError у тестовому середовищі ...


Яке значення ви намагаєтеся додати?
lpapp

додаючи значення а тестовий набору не переривання
JONO

2

В ідеалі ми не повинні обробляти / вловлювати помилки. Але можуть бути випадки, коли нам це потрібно робити, виходячи з вимог рамки чи застосування. Скажімо, у мене демон XML Parser, який реалізує DOM Parser, який споживає більше пам'яті. Якщо є така вимога, як нитка Parser, не слід загинути, коли вона отримує OutOfMemoryError , замість цього вона повинна обробляти її та надсилати повідомлення / пошту адміністратору програми / фреймворку.


1

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


1

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


1

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

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

Ви також зменшите читабельність свого коду.

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