Comment rendre une classe Java immuable, quel est le besoin d'immuabilité et y a-t-il un avantage à l'utiliser?
java
string
immutability
JavaUser
la source
la source
@Immutable
annotation de jcabi-aspectsRéponses:
Qu'est-ce qu'un objet immuable?
Un objet immuable est celui qui ne changera pas d'état après avoir été instancié.
Comment rendre un objet immuable?
En général, un objet immuable peut être créé en définissant une classe dont aucun de ses membres n'est exposé et qui n'a pas de setters.
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 une référence à un tableau ou
ArrayList
être obtenue via 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 le
ArrayList
peut être obtenu à traversgetList
et être manipulé, ce qui conduit à modifier l'état de l'objet lui-même, donc pas 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 avec la concurrence. Il est difficile de maintenir l'exactitude des objets mutables, car plusieurs threads pourraient essayer de changer l'état du même objet, ce qui conduit certains threads à voir un état différent du même objet, en fonction de la synchronisation des lectures et des écritures sur ledit objet. 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.
la source
return Collections.unmodifiableList(list);
renvoyer une vue en lecture seule sur la liste.final
aussi. Sinon, il peut être étendu avec une méthode setter (ou d'autres types de méthodes de mutation et de champs mutables).final
si la classe ne contient que desprivate
champs car ils ne sont pas accessibles depuis les sous-classes.En plus des réponses déjà données, je recommanderais de lire sur l'immuabilité dans Effective Java, 2e éd., Car certains détails sont faciles à manquer (par exemple, des copies défensives). De plus, Effective Java 2nd Ed. est une lecture incontournable pour chaque développeur Java.
la source
Vous rendez 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 les conditions requises pour rendre une classe Java immuable:
final
(pour que les classes enfants ne puissent pas être créées)final
(pour que nous ne puissions pas en changer la valeur après la création de l'objet)Les classes immuables sont utiles car
- Elles sont thread-safe.
- Ils expriment également quelque chose de profond à propos de votre conception: "Je ne peux pas changer cela."
la source
L'immuabilité peut être obtenue principalement de deux manières:
final
attributs d'instance pour éviter la réaffectationLes avantages de l'immuabilité sont les hypothèses que vous pouvez faire sur ces objets:
la source
Les classes immuables ne peuvent pas réaffecter les 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 la suite,
/** * 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
la source
Les classes immuables sont celles dont les objets ne peuvent pas être modifiés après la création.
Les classes immuables sont utiles pour
Exemple
Classe de chaîne
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; } }
la source
Comment rendre une classe Java immuable?
À partir du JDK 14+ qui a JEP 359 , nous pouvons utiliser "
records
". C'est le moyen le plus simple et le plus gratuit de créer une classe Immuable.Une classe d'enregistrement est un support transparent peu profond pour un ensemble fixe de champs connu sous le nom d'enregistrement
components
qui fournit unestate
description de l'enregistrement. Chacuncomponent
donne lieu à unfinal
champ qui contient la valeur fournie et uneaccessor
méthode pour récupérer la valeur. Le nom du champ et le nom de l'accesseur correspondent au nom du composant.Prenons l'exemple de la création d'un rectangle immuable
record Rectangle(double length, double width) {}
Pas besoin de déclarer un constructeur, pas besoin d'implémenter les méthodes equals & hashCode. Tous les enregistrements ont besoin d'un nom et d'une description d'état.
var rectangle = new Rectangle(7.1, 8.9); System.out.print(rectangle.length()); // prints 7.1
Si vous souhaitez valider la valeur lors de la création de l'objet, nous devons déclarer explicitement le constructeur.
public Rectangle { if (length <= 0.0) { throw new IllegalArgumentException(); } }
Le corps de l'enregistrement peut déclarer des méthodes statiques, des champs statiques, des initialiseurs statiques, des constructeurs, des méthodes d'instance et des types imbriqués.
Méthodes d'instance
record Rectangle(double length, double width) { public double area() { return this.length * this.width; } }
champs statiques, méthodes
Étant donné que l'état doit faire partie des composants, nous ne pouvons pas ajouter de champs d'instance aux enregistrements. Mais, nous pouvons ajouter des champs et des méthodes statiques:
record Rectangle(double length, double width) { static double aStaticField; static void aStaticMethod() { System.out.println("Hello Static"); } }
quel est le besoin d'immuabilité et y a-t-il un avantage à l'utiliser?
Les réponses précédemment publiées sont suffisamment bonnes pour justifier le besoin d'immuabilité et ce sont des avantages
la source
Une autre façon de rendre un objet immuable consiste à utiliser la bibliothèque Immutables.org :
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(); }
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) } }
la source
Une classe immuable est simplement une classe dont les instances ne peuvent pas être modifiées.
Toutes les informations contenues dans chaque instance sont fixes pour la durée de vie de l'objet, de sorte qu'aucun changement ne peut jamais être observé.
Les classes immuables sont plus faciles à concevoir, à implémenter et à utiliser que les classes mutables.
Pour rendre une classe immuable, suivez ces cinq règles:
Ne pas fournir de méthodes qui modifient l'état de l'objet
Assurez-vous que la classe ne peut pas être étendue.
Rendez tous les champs définitifs.
Rendre tous les champs privés.
Garantissez un accès exclusif à tous les composants mutables.
Les objets immuables sont intrinsèquement thread-safe; ils ne nécessitent aucune synchronisation.
Les objets immuables peuvent être partagés librement.
Les objets immuables constituent d'excellents blocs de construction pour d'autres objets
la source
@Jack, Avoir les champs finaux et les setters en classe ne rendra pas la classe immuable. Le mot clé final garantit uniquement qu'une variable n'est jamais réaffectée. Vous devez renvoyer une copie complète de tous les champs dans les méthodes getter. Cela garantira qu'après avoir obtenu un objet de la méthode getter, l'état interne de l'objet n'est pas perturbé.
la source
En tant que non-anglophone, je n'aime pas l'interprétation courante de «classe immuable» étant «les objets de classe construits sont immuables»; plutôt, je me penche moi-même pour interpréter cela comme «l'objet de classe lui-même est immuable».
Cela dit, la "classe immuable" est une sorte d'objet immuable. La différence réside dans la réponse à l'avantage. À ma connaissance / interprétation, la classe immuable empêche ses objets de modifier le comportement à l'exécution.
la source
La plupart des réponses ici sont bonnes, et certaines ont mentionné les règles, mais je pense qu'il est bon de mettre par écrit pourquoi et quand nous devons suivre ces règles. Alors je donne l'explication ci-dessous
Et bien sûr, si nous essayons d'utiliser Setters pour ces variables finales, le compilateur renvoie une erreur.
public class ImmutableClassExplored { public final int a; public final int b; /* OR Generally we declare all properties as private, but declaring them as public will not cause any issues in our scenario if we make them final public final int a = 109; public final int b = 189; */ ImmutableClassExplored(){ this. a = 111; this.b = 222; } ImmutableClassExplored(int a, int b){ this.a = a; this.b= b; } }
Avons-nous besoin de déclarer la classe comme «finale»?
1. N'ayant que des membres primitifs: nous n'avons pas de problème Si la classe n'a que des membres primitifs, alors nous n'avons pas besoin de déclarer la classe comme finale.
2. Avoir des objets comme variables membres: Si nous avons des objets comme variables membres, nous devons rendre les membres de ces objets également finaux. Cela signifie que nous devons traverser profondément dans l'arbre et rendre tous les objets / primitives comme finaux, ce qui peut ne pas être possible tout le temps. La solution de contournement consiste donc à rendre la classe définitive, ce qui empêche l'héritage. Il n'est donc pas question de sous-classe remplacer les méthodes getter.
la source
L'annotation @Value de Lombok peut être utilisée pour générer des classes immuables. C'est aussi simple que le code ci-dessous.
@Value public class LombokImmutable { int id; String name; }
Selon la documentation sur le site de Lombok:
Un exemple pleinement fonctionnel peut être trouvé ici.
la source
record
peut être utilisé?