Objets immuables en Java

Objets immuables en Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons découvrir ce qui rend un objet immuable, comment obtenir l'immuabilité en Java et quels sont les avantages qui en découlent.

2. Qu'est-ce qu'un objet immuable?

Un objet immuable est unobject whose internal state remains constant after it has been entirely created.

Cela signifie que l’API publique d’un objet immuable nous garantit qu’il se comportera de la même manière pendant toute sa durée de vie.

Si nous jetons un œil à la classeString, nous pouvons voir que même lorsque son API semble nous fournir un comportement mutable avec sa méthodereplace, leString d'origine ne change pas:

String name = "example";
String newName = name.replace("dung", "----");

assertEquals("example", name);
assertEquals("bael----", newName);

L'API nous donne des méthodes en lecture seule, elle ne devrait jamais inclure de méthodes qui modifient l'état interne de l'objet.

3. Le mot-cléfinal en Java

Avant d'essayer d'atteindre l'immuabilité en Java, nous devrions parler du mot-cléfinal.

En Java,variables are mutable by default, meaning we can change the value they hold.

En utilisant le mot-cléfinal lors de la déclaration d'une variable, le compilateur Java ne nous laisse pas changer la valeur de cette variable. Au lieu de cela, il signalera une erreur lors de la compilation:

final String name = "example";
name = "bael...";

Notez quefinal nous interdit uniquement de modifier la référence que contient la variable, cela ne nous empêche pas de modifier l'état interne de l'objet auquel il fait référence en utilisant son API publique:

final List strings = new ArrayList<>();
assertEquals(0, strings.size());
strings.add("example");
assertEquals(0, strings.size());

Le deuxièmeassertEquals échouera car l’ajout d’un élément à la liste modifie sa taille. Par conséquent, ce n’est pas un objet immuable.

4. Immuabilité en Java

Maintenant que nous savons comment éviter les modifications du contenu d'une variable, nous pouvons l'utiliser pour créer l'API d'objets immuables.

La création de l'API d'un objet immuable nous oblige à garantir que son état interne ne changera pas, quelle que soit la façon dont nous utilisons son API.

Un pas en avant dans la bonne direction consiste à utiliserfinal lors de la déclaration de ses attributs:

class Money {
    private final double amount;
    private final Currency currency;

    // ...
}

Notez que Java nous garantit que la valeur deamount ne changera pas, c’est le cas de toutes les variables de type primitif.

Cependant, dans notre exemple, nous avons seulement la garantie que lescurrency ne changeront pas, doncwe must rely on the CurrencyAPI to protect itself from changes.

La plupart du temps, nous avons besoin des attributs d'un objet pour contenir des valeurs personnalisées, et l'emplacement pour initialiser l'état interne d'un objet immuable est son constructeur:

class Money {
    // ...
    public Money(double amount, Currency currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public Currency getCurrency() {
        return currency;
    }

    public double getAmount() {
        return amount;
    }
}

Comme nous l'avons déjà dit, pour répondre aux exigences d'une API immuable, notre classeMoney ne dispose que de méthodes en lecture seule.

En utilisant l'API de réflexion, nous pouvons briser l'immuabilité et leschange immutable objects. Cependant, la réflexion enfreint l'API publique de l'objet immuable, et nous devons généralement éviter de le faire.

5. Avantages

Puisque l'état interne d'un objet immuable reste constant dans le temps,we can share it safely among multiple threads.

On peut aussi l'utiliser librement, et aucun des objets qui le référencent ne remarquera de différence, on peut dire queimmutable objects are side-effects free.

6. Conclusion

Les objets immuables ne changent pas leur état interne avec le temps, ils sont thread-safe et sans effets secondaires. En raison de ces propriétés, les objets immuables sont également particulièrement utiles pour les environnements multi-thread.

Vous pouvez trouver les exemples utilisés dans cet articleover on GitHub.