Geschiedenis van de kwestie:
In Java wordt onveranderlijkheid van collecties bereikt via wrappers zoals Collections.unmodifiableList() en het handmatig ontwerpen van immutable-klassen (final-velden, geen setters). In de praktijk van Android- en serverontwikkeling werd dit omslachtig en onhandig, en de threadveiligheid en voorspelbaarheid van gegevens gingen verloren.
Probleem:
Java-collecties zijn standaard niet veilig; je kunt altijd een referentie krijgen en het object wijzigen. Dit bemoeilijkt de controle over onveranderlijkheid, vooral in multithread-omgevingen, en leidt tot moeilijk te vangen bugs.
Oplossing:
Kotlin is oorspronkelijk ontworpen met een scheiding tussen read-only en mutabele collecties, en het creëren van werkelijk immutable objecten werd eenvoudiger met behulp van val, data class en List/Set/Map zonder de mutable-prefix. Bovenop dit alles — het gebruik van kopiëren via copy()-methoden.
Voorbeeldcode:
val nums: List<Int> = listOf(1, 2, 3) // onveranderlijke lijst // nums.add(4) // compilatiefout val user = User(name = "Alex", age = 30) val updated = user.copy(age = 31) // Voorbeeld met onveranderlijke map val state: Map<String, Int> = mapOf("a" to 1, "b" to 2)
Belangrijke kenmerken:
Garandeert val absolute onveranderlijkheid van het interne object?
Nee! val garandeert alleen dat de variabele niet naar een ander object kan verwijzen, maar de velden van het object kunnen worden gewijzigd (als de interne eigenschappen var zijn).
Is het mogelijk om een mutabel object te krijgen uit een read-only collectie?
Ja — als de collectie een mutabel object bevat, kun je zijn toestand wijzigen, ondanks de read-only interface van de collectie.
data class User(var name: String) val users: List<User> = listOf(User("Vasya")) users[0].name = "Petya" // toegestaan
Wat gebeurt er bij het casten van List<Int> naar MutableList<Int> via as?
Het compileert, maar zal leiden tot ClassCastException tijdens runtime, als het oorspronkelijke type een read-only interface was.
Een Android-applicatie slaat state op in val List<User>, denkend dat het onveranderlijk is. Een van de ontwikkelaars wijzigt user.name. In een ander fragment toont de bijgewerkte lijst plotseling inconsistente gegevens — een bug verschijnt in de release.
Voordelen:
Nadelen:
Gebruik van immutable data class alleen met val-velden, filtratie van toegang tot interne objecten, bijwerken van toestand via copy().
Voordelen:
Nadelen: