Pytanie Czy poprawnie korzystam z metody wypróbowania Java 7?


Spodziewam się, że buforowany czytnik i czytnik plików zostaną zamknięte, a zasoby zwolnione, jeśli wyjątek to rzut.

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 Klauzula pomyślnego zamknięcia?

EDYTOWAĆ:

Zasadniczo powyższy kod w Java 7 jest równoważny z poniższym dla Java 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;
}

76
2017-07-15 09:32


pochodzenie


Po ponownym przeczytaniu twojego pytania, nie jestem pewien, czy dobrze to rozumiem. Czy możesz to wyjaśnić? - Maroun
Cześć. Gepard, próbuję zrozumieć rolę pierwszego catch twojego przykładu dla Java 6. I.e. catch (Exception ex) { throw ex; } - po prostu rzuca wyjątek, nic nie robi, można go łatwo usunąć bez żadnych obrażeń. Czy może czegoś brakuje? - Sasha
W twojej składni nie ma nic złego. Jeśli chcesz dowiedzieć się więcej o try-with-resources, sprawdź ten artykuł: Java-try-with-resources - Hussein Terek


Odpowiedzi:


Jest poprawny i nie ma wymogu catch klauzula. Dokument Oracle java 7 mówi, że zasób zostanie zamknięty bez względu tego, czy wyjątek jest faktycznie rzucany, czy nie.

Powinieneś użyć a catch klauzula tylko wtedy, gdy chcesz zareagować na wyjątek. The catch klauzula zostanie wykonana po zasób jest zamknięty.

Oto fragment z Samouczek Oracle:

Poniższy przykład odczytuje pierwszą linię z pliku. Korzysta z   wystąpienie BufferedReader do odczytu danych z pliku. BufferedReader   jest zasobem, który należy zamknąć po zakończeniu programu   to:

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.

... Ponieważ instancja BufferedReader jest zadeklarowana jako   Instrukcja try-with-resource, będzie zamknięta niezależnie od tego, czy   instrukcja try kończy się normalnie lub nagle (w wyniku   metoda BufferedReader.readLine wyrzucająca wyjątek IOException).

EDYTOWAĆ

W odniesieniu do nowego edytowanego pytania:

Kod w Javie 6 wykonuje polecenie catch a następnie finally blok. Powoduje to, że zasoby są nadal potencjalnie otwarte w catch blok.

W składni języka Java 7 zasoby są zamykane przed  catch blokować, więc zasoby są już zamknięte podczas catch wykonanie bloku. Jest to udokumentowane w powyższym linku:

W instrukcji try-with-resources uruchamiany jest blok catch lub finally   po zamknięciu zadeklarowanych zasobów.


94
2017-07-15 09:40





Twoje użycie metody try-with-resources będzie działało dobrze w tym konkretnym przypadku, ale generalnie nie jest poprawne. Nie powinieneś łączyć takich zasobów, ponieważ może to prowadzić do nieprzyjemnych 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ś sz jest ujemny. W tym przypadku twój zasób pliku (utworzony przez new FileReader(filePath)) będzie NIE zamknięte.

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 w przypadku inicjalizacji br zawiedzie file wciąż jest zamknięty. Możesz znaleźć więcej szczegółów tutaj i tutaj.


65
2018-01-25 09:37



Próbuję zrozumieć, dlaczego zasoby utworzone przez new FileReader(filePath)) nie zamknie się w przypadku IllegalArgumentException jest wyrzucane, gdy sz jest ujemne. Czy próba z zasobami nie zamyka wszystkiego AutoClosable zasoby niezależnie od zgłaszanych wyjątków? - Prasoon Joshi
@PrasoonJoshi Nie, to tylko połączenia .close() dla zmiennych, które zostały zadeklarowane w inicjatorze try-for-resources. Dlatego rozdzielenie go na dwie deklaracje w tym przykładzie rozwiązuje problem. - Mario Carneiro
Andrii i @Mario Jesteście dobrzy i źle. W pierwszym przykładzie FileReader nie jest zamknięty przez logikę try-with-resource. Ale gdy bufor BufferReader zostanie zamknięty, to również zamknie owinięty FileReader. Aby uzyskać dowód, spójrz na źródło java.io.BufferedReader.close (). W związku z tym kod z pierwszego przykładu powinien być preferowany, ponieważ jest bardziej zwięzły. - jschreiner
@jschreiner To prawda, chociaż Andrija (nieco wymyślna) kwestia, w której sz < 0 powoduje, że konstruktor rzuca wyjątek w rzeczywistości spowoduje wyciek zasobów. - Mario Carneiro
@mario Zgadzam się. Zewnętrzny konstruktor może zawieść, a wewnętrzny zasób wycieknie. Nie widziałem tego wcześniej, dziękuję. - jschreiner