programowanieProgramista Android

Jak w Kotlin zrealizowana jest niemutowalność obiektów i czym różni się to od Javy? Podaj przykłady poprawnego i niepoprawnego podejścia, wyjaśnij możliwe niuanse pracy z obiektami niemutowalnymi.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

W Kotlinie przez niemutowalność zazwyczaj rozumie się niemożność zmiany stanu obiektu po jego utworzeniu. Osiąga się to poprzez użycie właściwości val (niemutowalnych) oraz przez tworzenie klas, które są inicjowane tylko w konstruktorze bez metod pozwalających na zmianę wewnętrznych danych.

Kotlin, w przeciwieństwie do Javy, oferuje wygodny mechanizm do tworzenia klas niemutowalnych za pomocą data class oraz takich kolekcji jak List, Set, Map (które domyślnie są niemutowalne). Ważne jest jednak, aby zrozumieć, że w Kotlinie podstawowe kolekcje są niemutowalne tylko na poziomie interfejsu, a sam obiekt kolekcji może być zmieniony, jeśli zostanie rzucony na MutableList itd.

Przykład poprawnej niemutowalności:

// Data class i val zapewniają niemutowalność data class User(val name: String, val age: Int) val user = User(name = "Ivan", age = 30) // user.name = "Sergey" // BŁĄD KOMPILACJI

Przykład kodu z naruszeniem niemutowalności:

class User(var name: String, var age: Int) val user = User("Ivan", 30) user.name = "Sergey" // Zmiana obiektu jest możliwa

Niuanse:

  • Nawet data class z polami val nie gwarantuje pełnej niemutowalności, jeśli pola to typy referencyjne, a ich wewnętrzny stan jest zmieniany.
  • Do prawdziwej niemutowalności używaj tylko val + niemutowalnych typów (np. val scores: List<Int>).

Pytanie z przymrużeniem oka.

Czy obiekty klasy data class z wyłącznie właściwościami val są całkowicie niemutowalne (immutable)?

Odpowiedź: Nie, jeśli właściwości to obiekty zmienne (np. val items: MutableList<Int>), wewnętrzny stan można zmieniać.

Przykład:

data class Group(val members: MutableList<String>) val group = Group(mutableListOf("Tom", "Jerry")) group.members.add("Spike") // wewnętrzny stan jest zmieniany

Przykłady realnych błędów wynikających z nieznajomości niuansów tematu.


Historia

W projekcie używano niemutowalnego data class z val właściwością typu MutableList. Jeden z programistów spodziewał się, że obiekt nie może być zmieniony, jednak inny programista dodał nowe elementy do kolekcji. Doprowadziło to do niespójności danych i trudnych do wykrycia błędów, gdy dwa wątki równolegle zmieniały wspólną listę.


Historia

Podczas przekazywania instancji klasy z zmienną kolekcją pomiędzy warstwami aplikacji, jedna warstwa zmieniała zawartość, nie powiadamiając drugiej warstwy. Spowodowało to sytuacje, w których UI nie wiedział o dokonanych zmianach i pracował z niewłaściwymi danymi źródłowymi.


Historia

Programista błędnie sądził, że List w Kotlinie jest zawsze niemutowalny. W rzeczywistości używano implementacji przekazanej z Javy (ArrayList), a próba zmiany listy doprowadziła do niespodziewanej utraty danych i błędów podczas pracy z bazą.