ProgrammationDéveloppeur Java

Qu'est-ce que les objets immuables en Java, quelle est leur valeur et comment implémenter correctement votre propre classe immuable ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Objets immuables — ce sont des objets dont l'état ne peut pas être modifié après leur création. Leurs principales caractéristiques :

  • Tous les champs sont final ;
  • Ils ne contiennent pas de mutateurs ;
  • On ne peut pas obtenir une référence mutable sur les objets internes (par exemple, les collections).

Avantages des objets immuables :

  • Sûrs pour l'accès multithread (thread-safe) ;
  • Faciles à mettre en cache et à réutiliser comme clés dans les collections ;
  • Simplifient le débogage et les tests ;
  • Moins de bugs dus à des modifications inattendues de l'état.

Exemple d'implémentation d'une classe immuable :

public final class Person { private final String name; private final int age; private final List<String> phones; public Person(String name, int age, List<String> phones) { this.name = name; this.age = age; // Protection contre la mutation de la liste transmise this.phones = Collections.unmodifiableList(new ArrayList<>(phones)); } public String getName() { return name; } public int getAge() { return age; } public List<String> getPhones() { return phones; } // Retourne une liste en lecture seule }

Question piège.

Pourquoi String est immuable en Java et que se passerait-il si ce n'était pas le cas ? Beaucoup de gens répondent "pour la sécurité", mais que cela signifie-t-il dans la pratique ?

Réponse :

String est utilisé dans de nombreux endroits : comme clés dans des collections, dans la logique de sécurité (par exemple, les mots de passe). Si une chaîne pouvait être modifiée via une référence, cela affecterait toutes les autres références au même objet, rendant impossible le bon fonctionnement des collections (par exemple, HashMap — lors du calcul de hashCode) et pouvant conduire à des vulnérabilités de sécurité.

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet.


Histoire

Dans un grand projet bancaire, des collections internes (liste des transactions) étaient transmises par un simple accesseur. En conséquence, la liste pouvait être modifiée de l'extérieur, violant des invariants (par exemple, ajouter une transaction avec une date incorrecte). Cela a conduit à une perte de données, jusqu'à ce qu'ils commencent à retourner Collections.unmodifiableList.

Histoire

Dans la classe de configuration racine, des champs-objets non protégés (Date, List) étaient stockés. Dans un des threads, la configuration a été modifiée, tandis que dans un autre, des données obsolètes ou inconsistantes ont été récupérées, ce qui a fait échouer incorrectement un algorithme métier.

Histoire

Dans un système de connexion, les mots de passe étaient stockés dans un objet mutable. En raison d'un accès non sécurisé, le mot de passe d'un autre utilisateur a soudainement été "fuit", car la même instance de l'objet était utilisée par plusieurs threads.