Cześć!
Wraz z dzisiejszym wpisem chciałbym zakończyć serię o słowach kluczowych w języku Java. Jeśli przegapiłeś poprzednie wpisy, zachęcam do nadrobienia zaległości:
- final (aby przeczytać post, kliknij tutaj),
- finally (aby przeczytać post, kliknij tutaj).
Już poraz ostatni zacytuje słynne zdanie z poprzednich wpisów: słowa kluczowe to jedno z częstych pytań w kontekśćie rekrutacji na java junior developerów. Pytanie brzmi zazwyczaj: “wymień różnicę między „final”, „finally” oraz „finalize” wraz z przykładami praktycznymi”.
W dzisiejszym wpisie na czynniki pierwsze rozłożymy słowo “finalize“, tym samym zamkniemy serię o słowach kluczowych – do dzieła!
Definicja
Metoda finalize jest metodą chronioną, zdefiniowaną w klasie Object. Wywoływana jest przez “Garbage Collector” na obiektach, do których nie ma już odwołań / referencji. Powszechnie nazywana jest po prostu “finalizatorem“. Tak jak w przypdadku każdej innej niefinalnej metody, możemy nadpisać tą metodę. Głównym celem “finalize” jest zwolnienie zasobów wykorzystywanych przez obiekty, zanim zostaną one usunięte z pamięci. Finalize może działać jako główny mechanizm dla operacji czyszczenia lub jako zabezpieczenie, gdy inne metody zakończą się niepowodzeniem.
Przykład
W celu lepszego zrozumienia działania “finalize“, przyjrzyjmy się praktycznemu przykładowi:
Klasa “Finalizator” posiada pole “czytacz“, które odwołuje się do zasobu “closeable“. Gdy tworzony jest obiekt z tej klasy, razem z nim tworzy się nowa instancja BufferedReader, która czyta z pliku w classpath.
Taka instancja używana jest w metodzie “czytajPierwszaLinie()” w celu przeczytania pierwszej linii w podanym pliku. Warto zauważyć, że w podanym kodzie nasz “czytacz” nie jest zamknięty. Można to zrobić za pomocą finalizatora:
Co udowodniono w powyższym przykładzie, nasz “finalize” jest zadeklarowany tak samo jak każda normalna metoda.
W praktycze czas, w którym “Garbage Collector” wywołuje wszystkie finalizatory, zależy od implementacji wirtualnej maszyny javy oraz warunków systemowych, na które zwyczajnei nie mamy wpływu.
W celu nauki i aby “Garbage Collector” zadziałał natychmiastowo, skorzystam również z metody System.gc(). W prawdziwych systemach nie powinniśmy wywoływać tej metody jawnie, ponieważ:
- wirtualna maszyna javy lepiej wie, kiedy “Garbage Collector” musi zostać wywołany,
- jest to kosztowne pod względem zasobów,
- nie powoduje to natychmiastowego działania “Garbage Collector” a jedynie jest to wskazówka dla wirtualnej maszyny javy żeby zacząć działać/
Poniżej wcześniej zapowiadany kod, demonstrujący przypadek testowy z udziałem finalizatora:
W pierwszej linii tworzony jest obiekt “Finalizator“, a następnie wywoływana jest jego metoda “czytajPierwszaLinie“. Obiekt nie jest przypisany do żadnej zmiennej, więc jak najbardziej kwalifikuje się do “wyczyszczenia” po przywołaniu “Garbage Collectora“.
Asercja w teście weryfikuje zawartość pliku wejściowego i jest używana tylko po to, aby udowodnić, że nasza klasa działa zgodnie z oczekiwaniami. W momencie uruchomienia testu, na konsoli pojawi się komunikat o zamknięciu czytnika w finalizatorze. Oznacza to, że metoda “finalize” została wywołana.
Powody, dla których powinniśmy unikać finalizatorów
Jak większość, wszystko ma swoje wady.
- wadą finalizatora jest szybkość jego działania a w zasadzie jego brak. Nigdy nie jesteśmy pewni, kiedy finalizator zostanie wykonany, ponieważ uruchomienie procesu “zbierania śmieci” może nastąpić w każdej chwili. Samo w sobie niest jest to problemem, ponieważ prędzej czy później finalizator zostanie wykonany. Jednakże zasoby systemowe niestety nie są ograniczone. Może się więc zdarzyć sytuacja, w której zabraknie zasobów zanim nastąpi czyszczenie, co może spowodować awarię naszej aplikacji.
- “finalize” ma również wpływ na “przenośność” programu. Dopóki “Garbage Collector” jest zależny od implementacji maszyny wirtualnej javy, to program może działać bardzo dobrze na jednym systemie, a na drugim zachowywać się już mniej wydajnie.
- “finalize” jest kosztowne pod względem wydajności. W szczególności, kiedy JVM musi wykonać o wiele więcej operacji podczas konstruowania i niszczenia obiektów zawierających niepusty finalizator.
- “finalize” nie obsługuje wyjątków. Jeśli finalizator rzuci wyjątek, proces finalizacji zostanie zatrzymany, pozostawiając obiekt w uszkodzonym stanie bez żadnego powiadomienia.
Podsumowanie
Pozdrawiam serdecznie,
biegajacyprogramista.pl