https://visualhunt.com/photo/192682/

Try-with-resources gdy nie ma AutoCloseable

Cześć! Kiedyś pisałem o tym, że chciałbym, aby ten blog był czymś na kształt mojego notatnika, do którego mogę wracać, gdzie bym się nie znalazł. Można dodać do tego założenie, że czas jaki poświęcę na przygotowanie i opublikowanie wpisu nie powinien przekroczyć jednej godziny – zobaczymy czy się uda:)

Do rzeczy. Na tapecie znalazła się konstrukcja try-with-resources, która dostępna jest, zdaje się od Javy SE 7. Zapewne jej składnia i przeznaczenie jest wszystkim znana – uproszczenie kodu dzięki braku konieczności korzystania z bloku finally instrukcji try-catch-finally, w której zamykane były zasoby wymagające takiej operacji. Dla zainteresowanych, po więcej szczegółów odsyłam do dokumentacji lub jak ktoś preferuje w języku polskim, do Samouczka Programisty.

Oczywiście można tworzyć swoje własne klasy, które implementują interfejs AutoCloseable, tak jak w przykładowej Operation1.

public class Operation1 implements Closeable{
    @Override
    public void close() {
        System.out.println("Operation 1: close");
    }
}

Dzięki temu, że klasa Operation1 implementuje interfejs java.io.Closeable, może być wykorzystana w klasycznym try-with-resources, podobnie jak przykładowa BufferedReader z pakietu java.io. Metoda close(), choć nie jest nigdzie jawnie wywołana, zostanie wykonana nawet w przypadku gdy w bloku try zdarzy się coś niespodziewanego.

try (Operation1 op1 = new Operation1()) {
            System.out.println("Operation 1 running");
            throw new Exception();
        } catch (Exception ex) {
            System.err.println("Exception occured.");
        }

Co w przypadku gdy korzystamy z zewnętrznego API? Może zdarzyć się sytuacja, w której operacja przez nas wykorzystywana, musi być zakończona metodą sprzątającą, zamykającą czy zwalniającą zasoby, natomiast nie implementuje ona interfejsu Closeable, tak jak w przypadku Operation2 oraz Operation3.

public class Operation2{
    public void close2() {
        System.out.println("Operation 2: close");
    }
}
public class Operation3{
    public void close() {
        System.out.println("Operation 3: close");
    }
}

W poniższym listingu zamieściłem przykładowe wykorzystanie powyższych operacji w konstrukcji try-with-resources. Pierwszy przypadek (Operation2) wykorzystuje wyrażenie lambda do wywołania metody close2(). Inną opcją jest wykorzystanie operatora :: przypisującego w tym wypadku do zmiennej closer, referencję do metody close() z klasy Operation3. Tutaj konieczna jest jedna uwaga, te elementy zostały wprowadzone dopiero od Javy SE w wersji 8.

public class TryWithResourcesRunner {
 
    public static void main(String[] args) {
        try (Operation1 op1 = new Operation1()) {
            System.out.println("Operation 1 running");
            throw new Exception();
        } catch (Exception ex) {
            System.err.println("Exception occured.");
        }
        System.out.println("---------------------------");
        Operation2 op2 = new Operation2();
        try (AutoCloseable closer = () -> op2.close2()) {
            System.out.println("Operation 2 running");
        } catch (Exception ex) {
            System.err.println("Exception occured.");
        }
        System.out.println("---------------------------");
        Operation3 op3 = new Operation3();
        try (AutoCloseable closer = op3::close) {
            System.out.println("Operation 3 running");
        } catch (Exception ex) {
            System.err.println("Exception occured.");
        }
        System.out.println("---------------------------");
    }
}

Na zakończenie podsumowanie działania metody main() prosto z konsoli. Jak widać, wszystko działa jak należy, w każdym z trzech przypadków, wywoływana jest metoda ‚sprzątająca’.

Operation 1 running
Operation 1: close
Exception occured.
---------------------------
Operation 2 running
Operation 2: close
---------------------------
Operation 3 running
Operation 3: close
---------------------------

Powyższy kod dostępny jest na GitHub.

Notatka zrobiona, samo napisanie zajęło około założonej jednej godziny. Do tego trzeba doliczyć jakieś korekty oraz znalezienie odpowiedniego obrazka wyróżniającego post, ale i tak nie jest źle. Polecam;) Zapraszam do śledzenia mojej aktywności na blogu, są plany częstszych publikacji!

Literatura obowiązkowa

Try-with-resources in Java 7
Java: close any type in try-with-resources using lambdas

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *