Първо, съжалявам, че зададохте въпроса какво трябвабъде добре износена тема. Натъкнах се на множество въпроси с отговори, които предполагат да преглътна (улавя и игнорира / регистрира) потенциално изключение от методи, които затварят ресурси в крайна сметка. Изглежда, това е общоприет модел. Но все още не съм виждал някой да обяснява защо, Ето само един пример: Опитайте-хвана-накрая и след това отново опитайте улов.
Разбрах, че всяко изключение, хвърлено от най-накрая блок, ще "маскира" всяко изключение, хвърлено в съответния пробен блок, но не виждам защо това е лошо нещо. Например:
Resource r = new Resource();
try {
r.use();
other();
} finally {
r.close();
}
Сегашното ми разбиране е:
- Ако само
close
хвърля изключение, определено не искаме да го преглътнем. - Ако и двете
use
иclose
хвърлете изключение, вероятно е по същата основна причина и няма значение кое изключение се разпространява (и двамата биха съдържали еднакво полезна информация?). - Ако и двете
other
иclose
хвърлете изключение, има два несвързани проблема. Може би този, който се е случил първо, трябва да се разпространява, но няма причина да предполага, че първото изключение причинен второто (има ли?), така че и двете ще направят.
За какво греша?
Отговори:
3 за отговор № 1Ако изключение хвърля само близко, определено не искаме да го преглътнем.
Това е вярно!
Ако и двамата използват и затварят изключение, това вероятно е по една и съща основна причина и няма значение кое изключение се разпространява (и двете биха съдържали еднакво полезна информация?).
Не точно. Изключението в try
можеше да бъде NullPointerException
, OutOfMemoryError
или действително изключение на I / O, описващо естеството на проблема. Дори и да е изключение за I / O, грешката може да остави потока в непоследователно състояние (или дори да го затвори преждевременно). close()
може да отстъпи напълно различна грешка, като „потокът вече е затворен","вътрешна грешка" или каквото и да е.
Една грешка в системата има тенденция да каскадира десеткина други, понякога изглеждат много несвързани. Винаги търсете първото изключение за първопричината. Останалото е просто боклук. Добър пример е инициализация, която се провали и остави обект в непоследователно състояние. По-късно виждате NullPointerException
е навсякъде, но истинският проблем възникна по-рано.
Ако и други, и близки хвърлят изключение, има два несвързани проблема. [...] няма някаква причина да се предполага, че първото изключение е причинило второто (има ли?), така че и двете ще го направят.
Всъщност, и двете изключения са вносът, но първият вероятно е по-подходящ. Решение? употреба AutoCloseable
ресурси в Java 7 и идиома с опитни ресурси, Ако по време на почистване възникне изключение, то ще бъде прикрепено към първоначалното изключение като подтиснат:
class Resource implements AutoCloseable //...
и тогава:
try(Resource r = new Resource()) {
r.use();
other();
}
Изключението ще изглежда така:
MyException: Exception in use()
at Resource.use(Main.java:11)
at Main.main(Main.java:16)
Suppressed: java.lang.RuntimeException: Exception in close()
at Main.close(Main.java:6)
at Main.main(Main.java:17)
}