Comment rendre une classe Java immuable, quel est le besoin d'immutabilité et y a-t-il un avantage à l'utiliser?
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.
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.
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:
final
(afin que des classes enfants ne puissent pas être créées)final
(afin que nous ne puissions pas changer sa valeur après la création de l'objet)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.
L’immuabilité peut être obtenue principalement de deux manières:
final
pour éviter une réaffectationLes avantages de l'immutabilité sont les hypothèses que vous pouvez faire sur ces objets:
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:
/**
* 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.
Classe immuable sont ceux dont les objets ne peuvent pas être modifiés après la création.
Les classes immuables sont utiles pour
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.
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)
}
}