Operator bezpiecznego wywołania '?.' jest jednym z kluczowych narzędzi do walki z wartościami null w Kotlinie i pojawił się jako rozwinięcie pomysłów języka, skoncentrowanego na zwiększeniu bezpieczeństwa i wygody pracy z potencjalnie brakującymi wartościami.
Historia pytania: W Javie wartości null często stają się źródłem błędów (NullPointerException). Kotlin wprowadził surowy system typów z wyraźnym wyróżnieniem zmiennych nullable i not-nullable oraz towarzyszył temu powstaniem narzędzi do ich wygodnego użycia.
Problem: Jak uniknąć NullPointerException podczas pracy z obiektami, które mogą być null, nie rezygnując z czytelności i zwięzłości kodu?
Rozwiązanie: Operator '?.' pozwala delikatnie odwoływać się do właściwości i metod zmiennych nullable: jeśli obiekt nie jest null, wywołanie zostaje wykonane, jeśli null — zwracane jest null (lub wymagana logika dalej).
Przykład kodu:
val user: User? = getUser() val name = user?.name // jeśli user != null, zwróci user.name, w przeciwnym razie null user?.printInfo() // jeśli user != null, wywoła printInfo()
Kluczowe cechy:
Czy operator bezpiecznego wywołania '?.' może być użyty po lewej stronie przypisania?
Nie. Operator '?.' nie może być użyty do bezpiecznego ustawienia wartości właściwości lub zmiennej; stosuje się go tylko do dostępu lub wywołania. Poniższe jest niepoprawne:
user?.name = "Alex" // Błąd kompilacji
Przypisania właściwości można przeprowadzać bezpiecznie za pomocą jawnej kontroli:
user?.let { it.name = "Alex" }
Co zwraca łańcuch operatorów safe call przy pierwszym napotkaniu null?
Gdy tylko jeden z elementów łańcucha '?.' jest równy null, wynik wyrażenia staje się null, dalsze wywołania safe call nie są realizowane.
Przykład:
user?.address?.zipCode // jeśli user lub address == null, wynik null
Czy można używać safe call '?.' z funkcjami, które zwracają Unit?
Tak, wywołanie i tak nastąpi tylko jeśli obiekt nie jest null, a zamiast Unit zwróci null, jeśli obiekt jest null.
Przykład:
user?.clearData() // jeśli user == null, nic się nie stanie
Programista stosuje '!!' tam, gdzie obiekt mógł być null, po długim łańcuchu safe call:
val country = user?.address?.city?.country!!
Zalety:
Wady:
Stosuje się safe call razem z operatorem Elvis, aby zwrócić domyślną wartość:
val country = user?.address?.city?.country ?: "Unknown"
Zalety:
Wady: