2009-01-06 11 views
14

Je fais souvent un champ de collecte non modifiable avant de le renvoyer à partir d'une méthode de lecture:Comment créer une collection profonde non modifiable?

private List<X> _xs; 
.... 
List<X> getXs(){ 
    return Collections.unmodifiableList(_xs); 
} 

Mais je ne peux pas penser à un moyen pratique de le faire si le X ci-dessus est lui-même une liste:

private List<List<Y>> _yLists; 
..... 
List<List<Y>> getYLists() { 
    return Collections.unmodifiableList(_yLists); 
} 

Le problème dans ce qui précède est bien sûr que, bien que le client ne peut pas modifier la liste des listes, il peut ajouter/supprimer des objets Y à partir des listes incorporées.

Des pensées?

Répondre

7

Le meilleur que je pourrais trouver utilise ForwardingList from Google Collections. Les commentaires sont les bienvenus.

private static <T> List<List<T>> unmodifiableList2(final List<List<T>> input) { 
    return Collections.unmodifiableList(new ForwardingList<List<T>>() { 
     @Override protected List<List<T>> delegate() { 
      return Collections.unmodifiableList(input); 
     } 
     @Override public List<T> get(int index) { 
      return Collections.unmodifiableList(delegate().get(index)); 
     } 
    }); 
} 
+0

C'est plutôt bien. –

+0

Surtout après avoir fait la liste externe non modifiable aussi :-) –

+1

Que se passe-t-il si c'est une liste d'ensembles? –

3

Malheureusement, il n'y a pas de moyen facile d'obtenir une constance profonde dans Java. vous devrez le contourner en vous assurant toujours que la liste de la liste est également non modifiable.

Je serais intéressé aussi de connaître une solution élégante.

+0

Et moi aussi! –

0

Si vous regardez l'implémentation des méthodes Collections.unmodifiable * (...), vous pouvez voir qu'elles ne font qu'emballer la collection. Faire une utilité profonde de la même manière devrait être faisable. L'inconvénient de ceci est qu'il ajoute un appel de méthode supplémentaire à l'accès à la collection et affecte ainsi les performances.

0

Si votre seul but est ici d'appliquer l'encapsulation, une solution classique consiste à utiliser clone() ou similaire à retourner une structure qui n'est pas l'état interne de l'objet. Cela ne fonctionne évidemment que si tous les objets peuvent être clonés, et si la structure copiée est suffisamment petite.

S'il s'agit d'une structure de données assez communément utilisée, une autre option consiste à rendre l'API qui y accède plus concrète, de sorte que vous disposiez d'un contrôle plus détaillé sur les appels spécifiques. Pour ce faire, vous pouvez écrire votre propre implémentation List, comme ci-dessus, mais pour restreindre les appels à des cas d'utilisation spécifiques, vous pouvez exposer des API d'accès spécifiques au lieu de l'interface List.

+0

Le problème avec la création de vos propres interfaces au lieu d'utiliser les interfaces Java standard est que vous ne pouvez pas tirer parti des nombreuses bibliothèques utilitaires qui utilisent les interfaces Java, à moins que vous ne les implémentiez également. À mon humble avis, c'est un prix trop élevé pour payer pour la constance profonde. – Chii

+0

La collection précitée (List of Lists) n'est pas une collection standard. – TREE

2

Les collections clojure (map, set, list, vector) peuvent toutes être imbriquées et sont immuables par défaut. Pour Java pur, il y a cette bibliothèque:

http://code.google.com/p/pcollections/

0

Juste au cas où quelqu'un est intéressé ici est une solution simple:

public List<List<Double>> toUnmodifiable(List<List<Double>> nestedList) { 
     List<List<Double>> listWithUnmodifiableLists = new ArrayList<>(); 
      for (List<Double> list : nestedList) {    
       listWithUnmodifiableLists 
        .add(Collections.unmodifiableList(list)); 
      } 
     return Collections.unmodifiableList(listWithUnmodifiableLists); 
    } 

Ceci peut être utilisé par exemple comme une solution si tu veux exposer une liste avec une méthode getList(), vous pouvez retourner: toUnmodifiable (mNestedList), où mNestedList est la liste privée de la classe.

Personnellement, j'ai trouvé cela utile lors de l'implémentation d'une classe utilisée pour analyser avec GSON dans Android, car cela n'a aucun sens de pouvoir modifier une réponse, dans ce cas le json désérialisé, j'ai utilisé cette méthode comme un moyen d'exposer la liste avec un getter et fait en sorte que la liste ne sera pas modifiée.

Questions connexes