web-dev-qa-db-fra.com

Classe immuable?

Comment rendre une classe Java immuable, quel est le besoin d'immutabilité et y a-t-il un avantage à l'utiliser?

78
JavaUser

Qu'est-ce qu'un objet immuable?

Un objet immuable est un objet qui ne changera pas d'état après son instanciation.

Comment rendre un objet immuable?

En général, un objet immuable peut être créé en définissant une classe dans laquelle aucun de ses membres n'est exposé ni aucun paramètre de définition.

La classe suivante créera un objet immuable:

class ImmutableInt {
  private final int value;

  public ImmutableInt(int i) {
    value = i;
  }

  public int getValue() {
    return value;
  }
}

Comme on peut le voir dans l'exemple ci-dessus, la valeur de ImmutableInt ne peut être définie que lorsque l'objet est instancié et, en n'ayant qu'un getter (getValue), l'état de l'objet ne peut pas être modifié après l'instanciation.

Cependant, il faut veiller à ce que tous les objets référencés par l'objet soient également immuables, sinon il pourrait être possible de changer l'état de l'objet. 

Par exemple, autoriser l'obtention d'une référence à un tableau ou à ArrayList par l'intermédiaire d'un getter permettra à l'état interne de changer en modifiant le tableau ou la collection:

class NotQuiteImmutableList<T> {
  private final List<T> list;

  public NotQuiteImmutableList(List<T> list) {
    // creates a new ArrayList and keeps a reference to it.
    this.list = new ArrayList(list); 
  }

  public List<T> getList() {
    return list;
  }
}

Le problème avec le code ci-dessus est que la ArrayList peut être obtenue via getList et être manipulée, ce qui entraîne une modification de l'état de l'objet lui-même, donc non immuable.

// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));

// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");

Une façon de contourner ce problème consiste à renvoyer une copie d'un tableau ou d'une collection lorsqu'elle est appelée à partir d'un getter:

public List<T> getList() {
  // return a copy of the list so the internal state cannot be altered
  return new ArrayList(list);
}

Quel est l'avantage de l'immuabilité?

L'avantage de l'immuabilité vient de la concurrence. Il est difficile de maintenir la correction dans les objets mutables, car plusieurs threads pourraient essayer de changer l'état du même objet, ce qui amènerait certains threads à voir un état différent du même objet, en fonction du minutage des lectures et des écritures. objet.

En ayant un objet immuable, on peut s'assurer que tous les threads qui regardent l'objet verront le même état, car l'état d'un objet immuable ne changera pas.

125
coobird

En plus des réponses déjà données, je vous recommanderais de vous renseigner sur l’immuabilité dans Effective Java, 2e édition, car il existe certains détails faciles à rater (copies défensives, par exemple). De plus, Effective Java 2nd Ed. est une lecture incontournable pour tous les développeurs Java.

18
Fabian Steeg

Vous faites une classe immuable comme ceci: 

public final class Immutable
{
    private final String name;

    public Immutable(String name) 
    {
        this.name = name;
    }

    public String getName() { return this.name; } 

    // No setter;
}

Voici la configuration requise pour rendre une classe Java immuable:

  • Class doit être déclaré en tant que final (afin que des classes enfants ne puissent pas être créées)
  • Members dans la classe doivent être déclarés en tant que final (afin que nous ne puissions pas changer sa valeur après la création de l'objet)
  • Ecrivez des méthodes Getter pour que toutes les variables qu'il contient aient les valeurs Members
  • Pas de méthode Setters 

Les classes immuables sont utiles car
- Ils sont thread-safe.
- Ils expriment également quelque chose de profond dans votre conception: "Vous ne pouvez pas changer cela.", Le cas échéant, c'est exactement ce dont vous avez besoin.

6
duffymo

L’immuabilité peut être obtenue principalement de deux manières:

  • en utilisant les attributs d'instance final pour éviter une réaffectation
  • en utilisant une interface de classe qui n'autorise aucune opération capable de modifier ce qui est à l'intérieur de votre classe (juste getters et no setters

Les avantages de l'immutabilité sont les hypothèses que vous pouvez faire sur ces objets:

  • vous obtenez la règle sans effet secondaire (qui est très populaire sur les langages de programmation fonctionnels) et vous permet d'utiliser les objets dans un environnement concurrent plus facilement, car vous savez qu'ils ne peuvent pas être modifiés de manière atomique ou non quand ils le sont utilisé par beaucoup de fils
  • les implémentations de langages peuvent traiter ces objets de manière différente, en les plaçant dans des zones de mémoire utilisées pour les données statiques, ce qui permet une utilisation plus rapide et plus sûre de ces objets (c'est ce qui se passe dans la JVM pour les chaînes).
5
Jack

Les classes immuables ne peuvent pas réaffecter des valeurs après leur instanciation. Le constructeur affecte des valeurs à ses variables privées. Jusqu'à ce que l'objet devienne nul, les valeurs ne peuvent pas être modifiées en raison de l'indisponibilité des méthodes de définition.

être immuable doit satisfaire aux exigences suivantes:

  • Toutes les variables doivent être private.
  • Aucune méthode mutator (setters) n'est fournie.
  • Evitez d’imposer des méthodes en rendant la classe finale (Immutabilité forte) Ou les méthodes finales (Immutabilité de la semaine).
  • Cloner profondément si elle contient des classes non primitives ou mutables.

/**
* Strong immutability - by making class final
*/
public final class TestImmutablity {

// make the variables private
private String Name;

//assign value when the object created
public TestImmutablity(String name) {
this.Name = name;
}

//provide getters to access values
public String getName() {

return this.Name;
}
}

Avantages: Les objets immuables contiennent leurs valeurs initialisées jusqu'à leur mort.

Java-immutable-classes-short-note

3
Kandy

Classe immuable sont ceux dont les objets ne peuvent pas être modifiés après la création.

Les classes immuables sont utiles pour

  • But de la mise en cache
  • Environnement concurrent (ThreadSafe)
  • Dur pour l'héritage
  • La valeur ne peut être modifiée dans aucun environnement

Exemple

Classe de cordes

Exemple de code

public final class Student {
    private final String name;
    private final String rollNumber;

    public Student(String name, String rollNumber) {
        this.name = name;
        this.rollNumber = rollNumber;
    }

    public String getName() {
        return this.name;
    }

    public String getRollNumber() {
        return this.rollNumber;
    }
}

En tant que anglophone non natif, je n'aime pas l'interprétation commune du terme "classe immuable", à savoir "les objets de classe construits sont immuables"; je me permets plutôt d'interpréter cela comme "l'objet de classe lui-même est immuable".

Cela dit, "classe immuable" est une sorte d'objet immuable. La différence réside dans le fait de répondre aux avantages. À ma connaissance/interprétation, la classe immuable empêche ses objets de modifier les comportements d'exécution.

0
bbgw

Une autre façon de créer un objet immuable consiste à utiliser Immutables.org library:

En supposant que les dépendances requises aient été ajoutées, créez un résumé classe avec méthodes abstraites d'accès. Vous pouvez faire la même chose en annoter avec des interfaces ou même des annotations (@interface):

package info.sample;

import Java.util.List;
import Java.util.Set;
import org.immutables.value.Value;

@Value.Immutable
public abstract class FoobarValue {
  public abstract int foo();
  public abstract String bar();
  public abstract List<Integer> buz();
  public abstract Set<Long> crux();
}

Il est maintenant possible de générer et d'utiliser ensuite l'immuable généré la mise en oeuvre:

package info.sample;

import Java.util.List;

public class FoobarValueMain {
  public static void main(String... args) {
    FoobarValue value = ImmutableFoobarValue.builder()
        .foo(2)
        .bar("Bar")
        .addBuz(1, 3, 4)
        .build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}

    int foo = value.foo(); // 2

    List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
  }
}
0
Justas