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:
val nie gwarantuje pełnej niemutowalności, jeśli pola to typy referencyjne, a ich wewnętrzny stan jest zmieniany.val + niemutowalnych typów (np. val scores: List<Int>).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
Historia
W projekcie używano niemutowalnego
data classzvalwłaściwością typuMutableList. 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
Listw 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ą.