Unveränderbare Java-Liste

8

Ich baue gerade einen LRU-Cache, in dem ich die letzten N eingefügten Elemente speichern muss. Elemente werden häufig eingefügt (d. H. Viele Schreiboperationen), und Leseoperationen geben typischerweise eine große Anzahl von Ereignissen immer strikt in der Reihenfolge zurück , obwohl sie an einem beliebigen Punkt im Cache beginnen. Angenommen, der Cache enthält Ereignisse:

%Vor%

Eine legale Leseoperation wäre die Rückgabe eines Iterators über die Ereignisse [2, 3, 4] .

Da Lesevorgänge möglicherweise langlebig sind, möchte ich eine Datenstruktur verwenden, in der ich sicher über eine logische Kopie der Sequenz für jeden Leseversuch iterieren kann, wodurch ein Lesevorgang im Cache verhindert wird von irgendwelchen nachfolgenden Schreibvorgängen. Wenn Sie jedoch ein Java-Java ArrayList oder LinkedList verwenden, entsteht beim Erstellen einer vollständigen Kopie ein großer Aufwand.

Meine Frage: Gibt es Java-Bibliotheken von Drittanbietern, die unveränderliche Datenstrukturen ähnlich wie Scala bereitstellen, wobei Versuche, die Datenstruktur zu ändern, eine neue unveränderliche -Kopie zurückgeben (die tatsächlich auf dem Original basiert) Datenstruktur und damit der Kopiervorgang ist sehr schnell)? Offensichtlich konnte die Datenstruktur nicht mit der API für Java-Sammlungen übereinstimmen, da Operationen wie add(T) die neue Sammlung zurückgeben müssten (anstatt void ).

(Bitte keine Kommentare / Antworten, die dies als Fall einer vorzeitigen Optimierung bezeichnen.)

Vielen Dank im Voraus.

Hinweis

Guavas ImmutableList erreicht fast das, was ich brauche: Sie können copyOf aufrufen, wobei die Kopie normalerweise auf das Original verweist (wobei eine tatsächliche Kopie vermieden wird). Leider können Sie nicht in die andere Richtung gehen und ein Element zur Liste hinzufügen und erhalten eine Kopie, die das neue Element enthält.

    
Adamski 07.07.2011, 11:49
quelle

7 Antworten

8

Functional Java kommt in Form einer Bibliothek (keine andere Sprache) und bietet unveränderliche Sammlungen. Nicht sicher, ob es Ihren Bedürfnissen entspricht, aber einen Versuch wert.

    
Sanjay T. Sharma 07.07.2011, 12:33
quelle
2

Haben Sie sich die CopyOnWriteArrayList angesehen? Jede Mutation in der Liste kopiert alle Inhalte in ein neues Backing-Array, wobei das aktuelle Array, auf dem Sie uninterpretiert werden, unverändert bleibt.

    
John Vint 07.07.2011 11:59
quelle
2

Es sieht so aus, als ob Sie hier eine einfach verknüpfte Liste implementieren möchten, die dann von verschiedenen Wrapper-Objekten gemeinsam genutzt werden kann. Möchten Sie jemals Elemente entfernen oder nur neue hinzufügen?

Wenn nur hinzugefügt und nicht entfernt wird, nehme ich an, dass eine einfachere Variante von CopyOnWriteArrayList, die nur dann die Kopie erstellt, wenn das alte Array voll ist, ausreichen könnte. Die Methoden sublist() würden dann einfach ein neues Wrapper-Objekt erstellen.

%Vor%

Wenn dies von mehreren Threads geändert wird, sollten Sie die add Methode synchronisiert und die len Variable volatile , denke ich. (Ich habe nicht komplett überprüft, ob es dann threadsicher ist.)

    
Paŭlo Ebermann 07.07.2011 15:23
quelle
2

Guave

Google Guava kann Ihre Anforderungen erfüllen.

Wenn Sie den Cache aktualisieren möchten, verwenden Sie Guavas Builder-Muster , um einen neuen Cache aus dem alten zu erstellen, und löschen Sie dann den alten Cache.

Um den Cache zu aktualisieren, erstellen Sie eine ImmutableList.Builder() und initialisieren Sie es mit Ihrer vorhandenen ImmutableList . Ändern Sie die Liste über die Builder-Benutzeroberfläche. Rufen Sie dann .build() auf, um eine neue ImmutableList zu erhalten, und löschen Sie den alten Cache. Der neue Cache wird alle alten Objekte wiederverwenden. Dies ist eine sehr einfache Operation.

Wenn jemand eine unveränderbare Kopie des Caches (oder eines seiner Elemente) haben möchte, geben Sie copyOf () zurück und sie erhalten Zugriff auf einen unveränderlichen Snapshot.

Achtung, wenn Sie mit Threads arbeiten, vergewissern Sie sich, dass Sie die Liste in ein Objekt einfügen und synchronisieren Sie es mit get () & amp; insert () - Methoden.

Weitere Informationen finden Sie unter auf der Guava-Website .

    
mstahl 15.05.2012 23:50
quelle
2

JDK 9 hat neue of() Methoden Factories. Z.B. Sie können ein unveränderliches Set haben als

%Vor%

Sie können das gleiche mit einer Liste machen, z. B.

%Vor%

und ein Map :

%Vor%     
JeanValjean 21.09.2017 20:47
quelle
1

Pure4J

Bietet unveränderbare Sammlungen über Kopien der persistenten Clojure-Sammlungsklassen. Es ist vielleicht nicht genau das, wonach Sie suchen, denn es geht darum, reine funktionale Semantik auf (Teilmengen von) Java-Programmen durchzusetzen.

Auf der anderen Seite hat es Unveränderlichkeitsgarantien für beide Elemente und Sammlungen. Wenn Sie ein Element aus einer Sammlung hinzufügen / entfernen, erhalten Sie eine neue Sammlung zurück und das Original bleibt unverändert.

    
Rob Moffat 04.11.2015 14:03
quelle