ProgrammationDéveloppeur Android Intermédiaire

Comment l'immuabilité des collections et des objets est-elle réalisée en Kotlin, et en quoi cela diffère-t-il de Java ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

Historique de la question :

En Java, l'immuabilité des collections est atteinte par le biais d'enveloppements tels que Collections.unmodifiableList() et la création de classes immuables manuellement (champs final, absence de setters). Dans la pratique du développement Android et serveur, cela est devenu coûteux et peu pratique, et la sécurité des threads ainsi que la prévisibilité des données étaient perdues.

Problème :

Les collections Java ne sont pas sécurisées par défaut, il est toujours possible d'obtenir une référence et de modifier l'objet. Cela complique le contrôle d'immuabilité, particulièrement dans des environnements multithreads, et entraîne des bugs difficiles à détecter.

Solution :

Kotlin a été dès le départ conçu avec une séparation des collections en read-only et mutable, et la création d'objets véritablement immuables est devenue plus simple grâce à val, data class et List/Set/Map sans le préfixe mutable. Par-dessus cela, l'utilisation de la copie via des méthodes copy().

Exemple de code :

val nums: List<Int> = listOf(1, 2, 3) // liste immuable // nums.add(4) // erreur de compilation val user = User(name = "Alex", age = 30) val updated = user.copy(age = 31) // Exemple avec un map immuable val state: Map<String, Int> = mapOf("a" to 1, "b" to 2)

Caractéristiques clés :

  • La compilation lors d'une tentative de modification d'une collection read-only générera une erreur
  • En Kotlin, val garantit l'immuabilité de la référence, mais pas nécessairement de l'objet
  • Pour être véritablement immuable, utilisez uniquement des interfaces read-only et interdisez la modification de l'état interne

Questions piégées.

val garantit-il une immuabilité absolue de l'objet imbriqué ?

Non ! val garantit seulement que la variable ne peut pas pointer vers un autre objet, mais les champs de l'objet peuvent être modifiés (si les propriétés internes sont var).

Peut-on obtenir un objet mutable à partir d'une collection read-only ?

Oui — si la collection contient un objet mutable, il est possible de modifier son état, malgré l'interface read-only de la collection.

data class User(var name: String) val users: List<User> = listOf(User("Vasya")) users[0].name = "Petya" // permis

Que se passera-t-il lors de la conversion de List<Int> en MutableList<Int> via as ?

Cela se compilera, mais conduira à une ClassCastException à l'exécution si le type d'origine était une interface read-only.

Erreurs typiques et anti-patrons

  • Prendre val pour une garantie absolue d'immuabilité de l'objet
  • Manipuler des références à des objets mutables à l'intérieur de collections "immutables"
  • Convertir des collections read-only en mutables

Exemple de la vie réelle

Cas négatif

Une application Android stocke l'état dans val List<User>, le considérant comme immuable. L'un des développeurs modifie user.name. Dans un autre fragment, la liste mise à jour montre alors des données incohérentes — le bug apparaît dans la version finale.

Avantages :

  • Travail rapide avec les collections

Inconvénients :

  • Perte de contrôle sur les mutations
  • Immutabilité masquée

Cas positif

Utilisation de classes de données immuables uniquement avec des champs val, filtrage de l'accès aux objets imbriqués, mise à jour de l'état via copy().

Avantages :

  • Haute prévisibilité et sécurité des threads
  • Absence d'effets secondaires inattendus

Inconvénients :

  • Parfois nécessite plus d'allocations et de copies
  • Toutes les bibliothèques tierces ne fournissent pas des objets véritablement immuables