web-dev-qa-db-fra.com

quel est le sens de final ArrayList?

Quels avantages/inconvénients pouvons-nous obtenir en rendant ArrayList (ou une autre collection) final? Je peux toujours ajouter à ArrayList de nouveaux éléments, supprimer des éléments et le mettre à jour. Mais quel est l’effet final? 

60
MyTitle

Mais quel est l’effet final?

Cela signifie que vous ne pouvez pas relier la variable pour qu'elle pointe vers une autre instance de collection:

final List<Integer> list = new ArrayList<Integer>();
list = new ArrayList<Integer>(); // Since `list' is final, this won't compile

Pour des raisons de style, je déclare que la plupart des références que je n’ai pas l’intention de changer en final.

Je peux toujours ajouter à ArrayList de nouveaux éléments, supprimer des éléments et le mettre à jour.

Si vous le souhaitez, vous pouvez empêcher l’insertion, le retrait, etc. en utilisant Collections.unmodifiableList() :

final List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>(...));
118
NPE

Cela signifie simplement que vous ne pouvez pas réaffecter sa référence. Essayer de faire quelque chose comme ce qui suit sera une erreur du compilateur.

final List<String> list = new ArrayList<String>();

list = new LinkedList<String>();
     ^
     Compiler error here

Si vous voulez vraiment une liste immuable, vous devriez utiliser la méthode Collections.unmodifiableList().

14
adarshr

Vous ne pourrez pas modifier sa référence à l'aide de new ArrayList par exemple.

8

final a beaucoup de conséquences en multi-threading.

  1. JMM définit clairement l’achèvement de l’initialisation d’un champ final est garanti.

Ce qui n'est pas clairement défini est:

  1. Les compilateurs sont libres de les réorganiser malgré les barrières de mémoire. 
  2. Les compilateurs peuvent toujours lire une copie en cache. 
5
user6765777

Créer la variable final permet de s'assurer que vous ne pouvez pas réaffecter cette référence d'objet après son affectation. Comme vous le mentionnez, vous pouvez toujours utiliser cette liste de méthodes pour apporter des modifications.

Si vous combinez le mot clé final avec l'utilisation de Collections.unmodifiableList , vous obtenez le comportement que vous essayez probablement d'obtenir, par exemple:

final List fixedList = Collections.unmodifiableList(someList);

En conséquence, la liste désignée par fixedList ne peut pas être modifiée. Attention cependant, cela peut toujours être changé avec la référence someList (assurez-vous donc que cela est hors de portée après cette affectation.)

5
rsp

Cela n’affecte pas ce que vous pouvez faire avec ArrayList comme vous le constatez à juste titre: l’ArrayList lui-même est toujours modifiable. Vous venez de faire la référence immuable.

Mais faire une finale variable a d'autres avantages:

  • Cela empêche la modification de la variable si elle doit rester constante. Cela peut aider à prévenir les futurs bugs.
  • Créer des variables final peut aider le compilateur à optimiser certaines performances.

En général, plus vous créez de choses immuables, mieux c'est. Donc, rendre les références définitives (même s’il s’agit de références à des objets mutables) est généralement une bonne idée.

3
mikera

Pour obtenir une liste vraiment immuable, vous devrez faire des copies complètes du contenu de la liste. UnmodifiableList rendrait seulement la liste de références quelque peu immuable . Maintenant, faire une copie en profondeur de la liste ou du tableau sera difficile pour la mémoire avec la taille croissante. Vous pouvez utiliser la sérialisation/désérialisation et stocker la copie complète de array/list dans un fichier temporaire. Le passeur ne serait pas disponible, le membre visible devant être immuable. Le getter sérialise la variable membre dans un fichier, puis le désialise pour en obtenir une copie complète. La séraialisation a la nature innée de pénétrer dans les profondeurs d'un arbre d'objets. Cela garantirait une immuabilité complète à un coût de performances cependant.

 package com.home.immutable.serial;

import Java.io.File;
import Java.io.FileInputStream;
import Java.io.FileNotFoundException;
import Java.io.FileOutputStream;
import Java.io.IOException;
import Java.io.ObjectInputStream;
import Java.io.ObjectOutputStream;
import Java.util.ArrayList;
import Java.util.List;

public final class ImmutableBySerial {

    private final int num;
    private final String str;
    private final ArrayList<TestObjSerial> immutableList;

    ImmutableBySerial(int num, String str, ArrayList<TestObjSerial> list){
        this.num = num;
        this.str = str;
        this.immutableList = getDeepCloned(list);
    }

    public int getNum(){
        return num;
    }

    public String getStr(){
        return str;
    }

    public ArrayList<TestObjSerial> getImmutableList(){
        return getDeepCloned(immutableList);
    }

    private ArrayList<TestObjSerial> getDeepCloned(ArrayList<TestObjSerial> list){
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        ArrayList<TestObjSerial> clonedObj = null;
        try {
             fos = new FileOutputStream(new File("temp"));
             oos = new ObjectOutputStream(fos);
             oos.writeObject(list);
             fis = new FileInputStream(new File("temp"));
             ois = new ObjectInputStream(fis);
             clonedObj = (ArrayList<TestObjSerial>)ois.readObject();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                oos.close();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return clonedObj;
    }
}
1
Rajeev Ranjan

Je marque personnellement le champ collections de mes classes avec final pour éviter aux utilisateurs de ma classe de vérifier s'il est nul ou non. Cela fonctionne car, une fois que la valeur est déjà affectée à une variable finale, elle ne peut jamais être réaffectée à une autre valeur, y compris null.

1
Bnrdo

Final est un mot clé ou un mot réservé en Java et peut être appliqué à variables membres, méthodes, classes et variables locales en Java. Une fois que vous faire une référence finale vous n'êtes pas autorisé à changer cette référence et le compilateur le vérifiera et générera une erreur de compilation si vous essayez pour réinitialiser les variables finales en Java.

1
lfergon

Vous ne pouvez pas le réassocier à une autre collection, comme le disait aix.

Exemple: En conjonction avec l'implémentation de liste immuable, vous obtenez des membres sécurisés que vous pouvez rendre publics.

Exemple: Lorsque vous vous appuyez sur cette référence ne change pas, vous avez besoin final. Cela est vrai dans les scénarios de synchronisation par exemple.

Il peut y avoir beaucoup plus d'exemples. C'est un bon style de déclarer les membres final si vous n'avez pas l'intention de changer la référence.

1
Fabian Barney

Essentiellement, ce que vous essayez de faire ici rend la liste immuable, je suppose. Cependant, lorsque vous marquez la référence de liste finale, cela signifie que la référence ne peut pas être pointée sur un autre objet de la liste autre que celui-ci.

Si vous voulez une ArrayList finale (immuable), utilisez plutôt la méthode utilitaire de la classe Collections, Collections.unmodifaibleList (list).

0
Adwivedi

Je suis venu à penser à cette même question et codé et exemple pour ajouter à l'explication sous un autre angle.

La liste finale de tableaux peut toujours être modifiée, reportez-vous à l'exemple ci-dessous et lancez-le pour voir par vous-même. 

Voici la classe immuable avec la déclaration de liste immuable:

public final class ImmutableClassWithArrayList {
 final List<String> theFinalListVar = new ArrayList<String>();
}

Et voici le pilote:

public class ImmutableClassWithArrayListTester {
public static void main(String[] args) {
    ImmutableClassWithArrayList immClass = new ImmutableClassWithArrayList();
    immClass.theFinalListVar.add("name");
    immClass.theFinalListVar.forEach(str -> System.out.println(str));
 }
}

Comme vous pouvez le constater, la méthode principale consiste à ajouter (modifier) ​​la liste. La seule chose à noter est donc que la "référence" à l'objet du type de collection ne peut pas être réaffectée à un autre de ces objets. Comme dans la réponse ci-dessus, vous ne pouvez pas faire immClass.theFinalListVar = new ArrayList (); dans la méthode principale ici.

La partie modification m'a vraiment aidé à comprendre cela et espère que cela aidera de la même manière.

0
Nirmal