Oczekuję, że buforowany czytnik i czytnik plików zostaną zamknięte, a zasoby zwolnione, jeśli wyjątek zostanie zgłoszony.
public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
{
return read(br);
}
}
Czy jednak istnieje wymóg posiadania catch
klauzuli umożliwiającej skuteczne zamknięcie?
EDYTOWAĆ:
Zasadniczo powyższy kod w Javie 7 jest odpowiednikiem poniższego kodu w Javie 6:
public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
BufferedReader br = null;
try
{
br = new BufferedReader(new FileReader(filePath));
return read(br);
}
catch (Exception ex)
{
throw ex;
}
finally
{
try
{
if (br != null) br.close();
}
catch(Exception ex)
{
}
}
return null;
}
java-7
try-with-resources
Gepard
źródło
źródło
catch
z twojego przykładu dla Java 6. Tj.catch (Exception ex) { throw ex; }
- to po prostu ponowne wyrzucenie wyjątku, nic nie robi, można go łatwo usunąć bez żadnego bólu. A może coś mi brakuje?Odpowiedzi:
Jest poprawna i nie ma wymogu
catch
klauzuli. Dokument Oracle java 7 mówi, że zasób zostanie zamknięty niezależnie od tego, czy wyjątek zostanie faktycznie zgłoszony, czy nie.catch
Klauzuli należy używać tylko wtedy, gdy chcesz zareagować na wyjątek.catch
Klauzula zostanie wykonana po zasób jest zamknięta.Oto fragment z samouczka Oracle :
static String readFirstLineFromFile(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } } // In this example, the resource declared in the try-with-resources statement is a BufferedReader.
EDYTOWAĆ
Odnośnie nowego zredagowanego pytania:
Kod w Javie 6 wykonuje blok,
catch
a następniefinally
. Powoduje to, że zasoby są nadal potencjalnie otwarte wcatch
bloku.W 7 składni Javy, zasoby są zamknięte przed tym
catch
blokiem, więc zasoby są już zamknięte podczascatch
wykonywania bloku. Jest to udokumentowane w powyższym linku:źródło
Korzystanie z zasobów typu „try-with-resources” będzie działać dobrze w tym konkretnym przypadku, ale ogólnie nie jest całkiem poprawne. Nie powinieneś łączyć zasobów w taki sposób, ponieważ może to prowadzić do niemiłych niespodzianek. Załóżmy, że masz zmienny rozmiar bufora:
public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException { int sz = /* get buffer size somehow */ try (BufferedReader br = new BufferedReader(new FileReader(filePath), sz)) { return read(br); } }
Załóżmy, że coś poszło nie tak i skończyłeś z
sz
negatywnym wynikiem . W takim przypadku Twój zasób plikowy (utworzony przeznew FileReader(filePath)
) NIE zostanie zamknięty.Aby uniknąć tego problemu, należy określić każdy zasób osobno w następujący sposób:
public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException { int sz = /* get buffer size somehow */ try (FileReader file = new FileReader(filePath); BufferedReader br = new BufferedReader(file, sz)) { return read(br); } }
W tym przypadku, nawet jeśli inicjalizacja
br
awariifile
nadal zostanie zamknięta. Więcej szczegółów znajdziesz tutaj i tutaj .źródło
new FileReader(filePath))
nie zamyka się w przypadkuIllegalArgumentException
wyrzucenia an, gdy sz jest ujemne. Czy próba z zasobami nie zamyka wszystkichAutoClosable
zasobów niezależnie od rzuconych wyjątków?.close()
zmienne, które zostały zadeklarowane w inicjatorze try-with-resources. Dlatego w tym przykładzie rozdzielenie go na dwie deklaracje załatwia sprawę.sz < 0
konstruktor wyrzuca wyjątek, w rzeczywistości spowoduje wyciek zasobu.