2009-01-06 7 views
14

Ich mache oft eine Sammlung Feld nicht änderbar, bevor es von einem Getter-Methode zurückkehrt:Wie erstelle ich eine tiefe, nicht veränderbare Sammlung?

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

Aber ich kann das nicht denken Sie an eine bequeme Art und Weise zu tun, wenn das X oben ist selbst eine Liste:

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

Das Problem in den obigen ist natürlich, dass, obwohl der Client die Liste der Listen nicht ändern kann, kann Y-Objekte hinzufügen/löschen von den eingebetteten Listen.

Irgendwelche Gedanken?

Antwort

7

Das beste, was ich mir vorstellen konnte, ist . Kommentare sind willkommen.

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

Das ist ziemlich gut. –

+0

Besonders nachdem ich die äußere Liste auch nicht änderbar gemacht habe :-) –

+1

Was passiert, wenn es sich um eine Liste von Sets handelt? –

3

Leider gibt es keinen einfachen Weg, um tiefe Const-Ness in Java zu bekommen. Sie müssten es hacken, indem Sie immer sicherstellen, dass die Liste in der Liste auch nicht änderbar ist.

würde mich auch interessieren, irgendeine elegante Lösung zu kennen.

+0

Und ich auch! –

0

Wenn Sie sich die Implementierung der Collections.unmodiable * (...) -Methoden ansehen, können Sie sehen, dass sie die Sammlung einfach umbrechen. Es sollte machbar sein, ein tiefes Dienstprogramm auf die gleiche Weise zu tun.

Der Nachteil davon ist, dass es zusätzlichen Methodenaufruf zum Sammelzugriff hinzufügt und so die Leistung beeinträchtigt.

0

Wenn Ihr nur hier Ziel Verkapselung zu erzwingen ist, eine klassische Lösung ist Klon() zu verwenden oder ähnliche eine Struktur zurück, die nicht den internen Zustand des Objekts ist. Dies funktioniert natürlich nur, wenn alle Objekte geklont werden können und wenn die kopierte Struktur klein genug ist.

Wenn dies eine ziemlich häufig verwendete Datenstruktur ist, besteht eine andere Möglichkeit darin, die API, die auf sie zugreift, konkreter zu machen, so dass Sie die spezifischen Aufrufe detaillierter steuern können. Schreiben Sie Ihre eigene List-Implementierung, wie oben ist eine Möglichkeit, dies zu tun, aber wenn Sie die Aufrufe auf bestimmte Anwendungsfälle einzugrenzen können Sie bestimmte Zugriffs-APIs anstelle der List-Schnittstelle verfügbar machen.

+0

das Problem mit dem Erstellen eigener Schnittstellen anstelle der Verwendung der Standard-Java-Einsen ist, dass Sie nicht die vielen Utility-Bibliotheken nutzen können, die die Java-Schnittstellen verwenden, es sei denn, Sie haben sie auch implementiert. IMHO, das ist ein Preis, der zu hoch ist, um für tiefe Konstanz zu bezahlen. – Chii

+0

Die angegebene Sammlung (List of Lists) ist keine Standard-Sammlung. – TREE

2

Die Clojure-Sammlungen (Karte, Satz, Liste, Vektor) können alle verschachtelt sein und sind standardmäßig unveränderlich. Für reine Java, gibt es diese Bibliothek:

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

0

Nur falls jemand hier interessiert, ist eine einfache Lösung:

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); 
    } 

Dies kann als eine Lösung zum Beispiel verwendet werden, wenn u wollen Wenn Sie eine Liste mit einer getList() -Methode bereitstellen, können Sie Folgendes ausgeben: toUnmodifyable (mNestedList), wobei mNestedList die private Liste in der Klasse ist.

Ich persönlich fand dies nützlich beim Implementieren einer Klasse für das Parsen mit GSON in Android, da es keinen Sinn macht, eine Antwort zu modifizieren, in diesem Fall die deserialisierte Json, habe ich diese Methode als verwendet eine Möglichkeit, die Liste mit einem Getter anzuzeigen und sicherzustellen, dass die Liste nicht geändert wird.

Verwandte Themen