Delikatny do przetrawienia artykuł z cyklu Javy, w którym pochylimy się nad wartością pustą, czyli czym naprawdę jest "null" w języku Java. Zapraszam po wyjaśnienia 😉!
TAJEMNICZE "NULL" W JĘZYKU JAVA TEŻ JEST CZĘSTYM GOŚCIEM W KODZIE
Powyższe słówko kluczowe jest bezpośrednio związane z klasami i referencjami, więc zapraszam najpierw tam po uzupełnienie wiedzy, jeżeli jeszcze nie kumasz obiektowości 👈.
Definiując sobie zmienną typu klasowego, oprócz posłusznego przypisania referencji do obiektu, możesz też przypisać wartość "null", które jest tematem artykułu:
MyClass mc = null;
Co to może znaczyć 🤔? Powszechnie (nie tylko w tym języku) "null" uznaje się za brak referencji do obiektu. Zwykle gdy zmienna posiada wskaźnik do obiektu, to na jego podstawie może "odnaleźć" obiekt, abyśmy mogli wykonać na nim pewne czynności. Kiedy program natrafi na "null", to dochodzi do wniosku, że nie ma do czego się odwołać i ta sytuacja przynosi swoje konsekwencje w momencie próby powołania się na obiekt, którego nie ma 😟!
OBRAZ SYTUACJI NIEBEZPIECZNEJ
"null" w języku Java powoduje zgłoszenie wyjątku "NullPointerException" w momencie powołania się na dowolną składową obiektu:
MyClass mc = null;
mc.doSomething(); // zgłoszenie wyjątku
Przy tak oczywistej sprawie, nawet samo IDE może Ci podpowiedzieć, że ta instrukcja wywoła problemy, natomiast gorzej z wyłapaniem takiej możliwości kiedy jakaś metoda zwraca obiekt i dla jakiejś wyjątkowej sytuacji może zwrócić "null":
MyClass mc = objectInstance();
mc.doSomething(); // zgłoszenie wyjątku
SPOSOBY ZAPOBIEGANIA
Najlepszym z nich jest prosty: zapewnić, że zawsze w każdej sytuacji zostanie zwrócona jakaś referencja 😊. Szczególnie to dotyczy struktur danych - jeżeli dla przykładu masz tablicę z danymi, to zamiast wartości "null" możesz zwrócić pustą tablicę 💡. Kiedy nie możemy tego zagwarantować, to mamy parę wariantów.
INSTRUKCJA WARUNKOWA POD OBECNOŚĆ WARTOŚCI "NULL"
Często uprawianą praktyką jest objęcie instrukcji w instrukcję warunkową sprawdzającą czy zmienna nie jest równa "null":
MyClass mc = objectInstance();
if(mc != null) {
mc.doSomething();
}
To zabezpieczy program przed wywaleniem wyjątku typu "NullPointerException" (wskaźnik nieodwołujący się do jakiegokolwiek obiektu zgodnego z typem danych). Jest to najprostszy sposób, choć wielokrotne sprawdzanie obecności wartości "null" w języku Java dla każdej zmiennej z osobna jest męczące i przede wszystkim, pogarsza czytelność kodu.
ZWRACANIE OBIEKTU "DOMYŚLNEGO"
Drugi sposób to zwrócenie na wyjściu obiektu "domyślnego" kiedy wszystkie inne przypadki zawiodły w danej metodzie i nie ma czego zwrócić:
public MyClass objectInstance() {
// wszystkie inne przypadki zwracania obiektów konkretnych
return new MyClass(); // zwrócenie obiektu "czystego" ("domyślnego")
}
Haczyk z kolei jest taki, że późniejsze instrukcje mające się wykonywać na tym obiekcie mogą niepotrzebnie marnować zasoby - to już zależy od kontekstu i należy to uwzględnić.
TYP "OPTIONAL"
Ostatnia metodą jaką przytoczę jest skorzystanie z typu "Optional", który został wprowadzony do Javy w wersji 8 (2014). Przy użyciu typu generycznego, podstawiamy naszą klasę i korzystając z wbudowanych metod "bronimy się" przed zwróceniem wartości "null" (użyłem zapisu z "Random", żeby wylosować 50% szansę na utworzenie obiektu 😆 - oczywiście to nie jest praktyczne podejście, lecz chciałem wymyślić szybki przykład 😜):
public Optional<MyClass> objectInstance() {
if(new Random().nextBoolean())
{
return Optional.of(new MyClass());
}
return Optional.empty(); // zwrócenie "pustego" obiektu (lecz nie wartości "null"!)
}
"Optional" wymaga importu pakietu:
import java. util.Optional;
Od drugiej strony TAKŻE trzeba napisać kod inaczej:
Optional<MyClass> mc = objectInstance();
mc.ifPresent(e -> {
e.setValue(13);
System.out.println(e);
});
Stosujemy wtedy metodę "ifPresent" i w środku nawiasów okrągłych stosujemy wyrażenie lambda (funkcję anonimową), czyli zestaw instrukcji do wykonania na tym obiekcie, lecz wtedy i tylko wtedy, gdy istnieje. Dzięki temu, nie musimy sami otaczać tego instrukcją warunkową, a sam kod wygląda o niebo lepiej ⛅. Traktuj to jak abstrakcyjną "otoczkę" wokół zwracanych wartości mającą na celu zabezpieczenie się przed wartością "null".
"null" w języku Java jest wartością pustą oznaczającą brak referencji do obiektu. Należy zadbać o ochronę przed próbą wykonania jakiejkolwiek instrukcji na obiekcie wskazującym na wartość "null", aby nie doprowadzić do zgłoszenia wyjątku.
Przypisanie wartości "null" powoduje również dodatkową rzecz: kiedy metoda, w której znajduje się zmienna wskazująca na wartość "null", zostanie zakończona, to zostaje przeznaczona do usunięcia przez wbudowany odśmiecacz pamięci. Jest to automatyczna czynność "sprzątania" po zaalokowanej pamięci, którą wykonujemy manualnie w językach C (funkcja "free") i C++ (słówko "delete") 😇.
To wszystko co chciałem przekazać na ten temat ✔️.