Guide zur Collections-API in Vavr

Leitfaden zur Sammlungs-API in Vavr

1. Überblick

Die Vavr-Bibliothek, früher als Javaslang bekannt, ist eine Funktionsbibliothek für Java. In diesem Artikel untersuchen wir die leistungsstarke API für Sammlungen.

Um weitere Informationen zu dieser Bibliothek zu erhalten, lesen Sie bittethis article.

2. Persistente Sammlungen

Wenn eine persistente Sammlung geändert wird, wird eine neue Version der Sammlung erstellt, wobei die aktuelle Version beibehalten wird.

Das Verwalten mehrerer Versionen derselben Sammlung kann zu einer ineffizienten CPU- und Speichernutzung führen. Die Vavr-Auflistungsbibliothek überwindet dies jedoch, indem sie die Datenstruktur für verschiedene Versionen einer Auflistung freigibt.

Dies unterscheidet sich grundlegend von JavaunmodifiableCollection() von derCollectionsUtility-Klasse, die lediglich einen Wrapper um eine zugrunde liegende Sammlung bereitstellt.

Der Versuch, eine solche Sammlung zu ändern, führt zuUnsupportedOperationException, anstatt dass eine neue Version erstellt wird. Darüber hinaus ist die zugrunde liegende Sammlung durch ihren direkten Bezug noch veränderbar.

3. Traversable

Traversable ist der Basistyp aller Vavr-Sammlungen. Diese Schnittstelle definiert Methoden, die von allen Datenstrukturen gemeinsam genutzt werden.

Es bietet einige nützliche Standardmethoden wiesize(),get(),filter(),isEmpty() und andere, die von Subschnittstellen geerbt werden.

Lassen Sie uns die Sammlungsbibliothek weiter erkunden.

4. Seq

Wir beginnen mit Sequenzen.

DieSeq-Schnittstelle repräsentiert sequentielle Datenstrukturen. Es ist die übergeordnete Schnittstelle fürList,Stream,Queue,Array,Vector undCharSeq. Alle diese Datenstrukturen haben ihre eigenen einzigartigen Eigenschaften, die wir im Folgenden untersuchen werden.

4.1. List

AList ist eine eifrig evaluierte Folge von Elementen, die dieLinearSeq-Schnittstelle erweitern.

PersistenteLists werden rekursiv aus einem Kopf und einem Schwanz gebildet:

  • Kopf - das erste Element

  • Schwanz - eine Liste mit verbleibenden Elementen (diese Liste wird auch aus einem Kopf und einem Schwanz gebildet)

In derList-API gibt es statische Factory-Methoden, mit denenList erstellt werden können. Wir können die statische Methodeof() verwenden, um eine Instanz vonList aus einem oder mehreren Objekten zu erstellen.

Wir können auch die statischenempty() verwenden, um ein leeresList zu erstellen, undofAll(), um einList aus einemIterable-Typ zu erstellen:

List list = List.of(
  "Java", "PHP", "Jquery", "JavaScript", "JShell", "JAVA");

Schauen wir uns einige Beispiele zum Bearbeiten von Listen an.

Wir können diedrop() und ihre Varianten verwenden, um die erstenN-Elemente zu entfernen:

List list1 = list.drop(2);
assertFalse(list1.contains("Java") && list1.contains("PHP"));

List list2 = list.dropRight(2);
assertFalse(list2.contains("JAVA") && list2.contains("JShell"));

List list3 = list.dropUntil(s -> s.contains("Shell"));
assertEquals(list3.size(), 2);

List list4 = list.dropWhile(s -> s.length() > 0);
assertTrue(list4.isEmpty());

drop(int n) entferntn Anzahl der Elemente aus der Liste ab dem ersten Element, währenddropRight() dasselbe ab dem letzten Element in der Liste tut.

dropUntil() entfernt weiterhin Elemente aus der Liste, bis das Prädikat als wahr ausgewertet wird, währenddropWhile() weiterhin Elemente löscht, während das Prädikat wahr ist.

Es gibt auchdropRightWhile() unddropRightUntil(), mit denen Elemente von rechts entfernt werden.

Als nächstes wirdtake(int n) verwendet, um Elemente aus einer Liste abzurufen. Es nimmtn Anzahl der Elemente aus der Liste und stoppt dann. Es gibt auch eintakeRight(int n), das Elemente am Ende der Liste übernimmt:

List list5 = list.take(1);
assertEquals(list5.single(), "Java");

List list6 = list.takeRight(1);
assertEquals(list6.single(), "JAVA");

List list7 = list.takeUntil(s -> s.length() > 6);
assertEquals(list7.size(), 3);

Schließlich nimmttakeUntil() weiterhin Elemente aus der Liste, bis das Prädikat wahr ist. Es gibt einetakeWhile()-Variante, die auch ein Prädikatargument akzeptiert.

Darüber hinaus gibt es andere nützliche Methoden in der API, z. B. tatsächlichdistinct(), die eine Liste nicht doppelter Elemente zurückgeben, sowiedistinctBy(), dieComparator akzeptieren, um die Gleichheit zu bestimmen.

Sehr interessant ist, dass es auchintersperse()gibt, die ein Element zwischen jedes Element einer Liste einfügen. Dies kann fürString-Operationen sehr praktisch sein:

List list8 = list
  .distinctBy((s1, s2) -> s1.startsWith(s2.charAt(0) + "") ? 0 : 1);
assertEquals(list8.size(), 2);

String words = List.of("Boys", "Girls")
  .intersperse("and")
  .reduce((s1, s2) -> s1.concat( " " + s2 ))
  .trim();
assertEquals(words, "Boys and Girls");

Möchten Sie eine Liste in Kategorien unterteilen? Nun, auch dafür gibt es eine API:

Iterator> iterator = list.grouped(2);
assertEquals(iterator.head().size(), 2);

Map> map = list.groupBy(e -> e.startsWith("J"));
assertEquals(map.size(), 2);
assertEquals(map.get(false).get().size(), 1);
assertEquals(map.get(true).get().size(), 5);

Dasgroup(int n) unterteilt einList in Gruppen von jeweilsn Elementen. DasgroupdBy() akzeptiert einFunction, das die Logik zum Teilen der Liste enthält, und gibt einMap mit zwei Einträgen zurück -true undfalse.

Der Schlüssel vontruewird einemListvon Elementen zugeordnet, die die inFunction;angegebene Bedingung erfüllen. Der Schlüssel vonfalsewird einemListvon Elementen zugeordnet, die dies nicht tun.

Wie erwartet wird beim Mutieren vonList das ursprünglicheList nicht tatsächlich geändert. Stattdessen wird immer eine neue Version vonList zurückgegeben.

Wir können auch mit aList mithilfe der Stapelsemantik interagieren - LIFO-Abruf (Last-In-First-Out) von Elementen. Insofern gibt es API-Methoden zum Bearbeiten eines Stapels wiepeek(),pop() undpush():

List intList = List.empty();

List intList1 = intList.pushAll(List.rangeClosed(5,10));

assertEquals(intList1.peek(), Integer.valueOf(10));

List intList2 = intList1.pop();
assertEquals(intList2.size(), (intList1.size() - 1) );

DiepushAll()-Funktion wird verwendet, um einen Bereich von ganzen Zahlen in den Stapel einzufügen, während diepeek() verwendet werden, um den Kopf des Stapels zu erhalten. Es gibt auch diepeekOption(), die das Ergebnis in einOption-Objekt einschließen können.

Es gibt andere interessante und wirklich nützliche Methoden in derList-Schnittstelle, die inJava docs übersichtlich dokumentiert sind.

4.2. Queue

Ein unveränderlicherQueue speichert Elemente, die einen FIFO-Abruf (First-In-First-Out) ermöglichen.

EinQueue besteht intern aus zwei verknüpften Listen, einem vorderenList und einem hinterenList. Das vordereList enthält die Elemente, die in die Warteschlange gestellt werden, und das hintereList enthält die Elemente, die in die Warteschlange gestellt werden.

Dadurch könnenenqueue- unddequeue-Operationen in O (1) ausgeführt werden. Wenn die vorderenList keine Elemente mehr haben, werden die vorderen und hinterenList’s vertauscht und die hinterenList werden umgekehrt.

Erstellen wir eine Warteschlange:

Queue queue = Queue.of(1, 2);
Queue secondQueue = queue.enqueueAll(List.of(4,5));

assertEquals(3, queue.size());
assertEquals(5, secondQueue.size());

Tuple2> result = secondQueue.dequeue();
assertEquals(Integer.valueOf(1), result._1);

Queue tailQueue = result._2;
assertFalse(tailQueue.contains(secondQueue.get(0)));

Die Funktiondequeue entfernt das Kopfelement ausQueue und gibtTuple2<T, Q> zurück. Das Tupel enthält das Kopfelement, das als erster Eintrag entfernt wurde, und die verbleibenden Elemente vonQueue als zweiten Eintrag.

Wir könnencombination(n) verwenden, um alle möglichenN Elementkombinationen inQueue zu erhalten:

Queue> queue1 = queue.combinations(2);
assertEquals(queue1.get(2).toCharSeq(), CharSeq.of("23"));

Wieder können wir sehen, dass das ursprünglicheQueue beim Einreihen / Ausreihen von Elementen nicht geändert wird.

4.3. Stream

AStream ist eine Implementierung einer faulen verknüpften Liste und unterscheidet sich erheblich vonjava.util.stream. Im Gegensatz zujava.util.stream speichert der VavrStream Daten und wertet die nächsten Elemente träge aus.

Nehmen wir an, wir habenStream von ganzen Zahlen:

Stream s = Stream.of(2, 1, 3, 4);

Wenn Sie das Ergebnis vons.toString() auf die Konsole drucken, werden nurStream(2, ?) angezeigt. Dies bedeutet, dass nur der Kopf derStream bewertet wurde, während der Schwanz nicht bewertet wurde.

Wenn Sies.get(3) aufrufen und anschließend das Ergebnis vons.tail() anzeigen, wirdStream(1, 3, 4, ?) zurückgegeben. Im Gegenteil, ohnes.get(3) erstes aufzurufen, wodurch dieStream das letzte Element auswerten - das Ergebnis vons.tail() ist nurStream(1, ?). Dies bedeutet, dass nur das erste Element des Schwanzes ausgewertet wurde.

Dieses Verhalten kann die Leistung verbessern und ermöglicht die Verwendung vonStream zur Darstellung von Sequenzen, die (theoretisch) unendlich lang sind.

VavrStream ist unveränderlich und kannEmpty oderCons sein. EinCons besteht aus einem Kopfelement und einem faulen berechneten SchwanzStream. Im Gegensatz zuList wird beiStream nur das Kopfelement gespeichert. Die Tail-Elemente werden bei Bedarf berechnet.

Erstellen wir einStream von 10 positiven ganzen Zahlen und berechnen wir die Summe der geraden Zahlen:

Stream intStream = Stream.iterate(0, i -> i + 1)
  .take(10);

assertEquals(10, intStream.size());

long evenSum = intStream.filter(i -> i % 2 == 0)
  .sum()
  .longValue();

assertEquals(20, evenSum);

Im Gegensatz zur Java 8Stream-API ist VavrsStreameine Datenstruktur zum Speichern einer Folge von Elementen.

Somit hat es Methoden wieget(),append(),insert() und andere zum Manipulieren seiner Elemente. Diedrop(),distinct() und einige andere zuvor berücksichtigte Methoden sind ebenfalls verfügbar.

Lassen Sie uns abschließend schnell dietabulate() inStream demonstrieren. Diese Methode gibtStream der Längen zurück, die Elemente enthält, die das Ergebnis der Anwendung einer Funktion sind:

Stream s1 = Stream.tabulate(5, (i)-> i + 1);
assertEquals(s1.get(2).intValue(), 3);

Wir können auchzip() verwenden, umStream vonTuple2<Integer, Integer> zu erzeugen, das Elemente enthält, die durch Kombinieren von zweiStreams gebildet werden:

Stream s = Stream.of(2,1,3,4);

Stream> s2 = s.zip(List.of(7,8,9));
Tuple2 t1 = s2.get(0);

assertEquals(t1._1().intValue(), 2);
assertEquals(t1._2().intValue(), 7);

4.4. Array

EinArray ist eine unveränderliche, indizierte Sequenz, die einen effizienten Direktzugriff ermöglicht. Es wird von Javaarray von Objekten unterstützt. Im Wesentlichen handelt es sich um einenTraversable-Wrapper für ein Array von Objekten vom TypT.

Wir können einArray mithilfe der statischen Methodeof() instanziieren. Wir können auch Bereichselemente mithilfe der statischen Methodenrange() undrangeBy() generieren. rangeBy() hat einen dritten Parameter, mit dem wir den Schritt definieren können.

Die Methodenrange() undrangeBy() generieren nur Elemente, die vom Startwert bis zum Endwert minus eins beginnen. Wenn wir den Endwert einschließen müssen, können wir entwederrangeClosed() oderrangeClosedBy() verwenden:

Array rArray = Array.range(1, 5);
assertFalse(rArray.contains(5));

Array rArray2 = Array.rangeClosed(1, 5);
assertTrue(rArray2.contains(5));

Array rArray3 = Array.rangeClosedBy(1,6,2);
assertEquals(rArray3.size(), 3);

Manipulieren wir die Elemente nach Index:

Array intArray = Array.of(1, 2, 3);
Array newArray = intArray.removeAt(1);

assertEquals(3, intArray.size());
assertEquals(2, newArray.size());
assertEquals(3, newArray.get(1).intValue());

Array array2 = intArray.replace(1, 5);
assertEquals(array2.get(0).intValue(), 5);

4.5. Vector

AVector ist eine Art ZwischenArray undList, die eine weitere indizierte Folge von Elementen bereitstellen, die sowohl einen wahlfreien Zugriff als auch eine Änderung in konstanter Zeit ermöglicht:

Vector intVector = Vector.range(1, 5);
Vector newVector = intVector.replace(2, 6);

assertEquals(4, intVector.size());
assertEquals(4, newVector.size());

assertEquals(2, intVector.get(1).intValue());
assertEquals(6, newVector.get(1).intValue());

4.6. CharSeq

CharSeq ist ein Sammlungsobjekt, um eine Folge primitiver Zeichen auszudrücken. Es handelt sich im Wesentlichen um einenString-Wrapper mit zusätzlichen Erfassungsoperationen.

So erstellen Sie einCharSeq:

CharSeq chars = CharSeq.of("vavr");
CharSeq newChars = chars.replace('v', 'V');

assertEquals(4, chars.size());
assertEquals(4, newChars.size());

assertEquals('v', chars.charAt(0));
assertEquals('V', newChars.charAt(0));
assertEquals("Vavr", newChars.mkString());

5. Set

In diesem Abschnitt werden verschiedeneSet-Implementierungen in der Sammlungsbibliothek erläutert. Das einzigartige Merkmal der Datenstruktur vonSetist, dass keine doppelten Werte zulässig sind.

Es gibt jedoch verschiedene Implementierungen vonSet - wobeiHashSet die grundlegende ist. DieTreeSet erlauben keine doppelten Elemente und können sortiert werden. DasLinkedHashSet behält die Einfügereihenfolge seiner Elemente bei.

Schauen wir uns diese Implementierungen nacheinander genauer an.

5.1. HashSet

HashSet verfügt über statische Factory-Methoden zum Erstellen neuer Instanzen - von denen einige bereits in diesem Artikel untersucht wurden - wieof(),ofAll() und Variationen vonrange()-Methoden.

Wir können den Unterschied zwischen zwei Mengen mit derdiff()-Methode ermitteln. Außerdem geben die Methodenunion() undintersect() die Vereinigungsmenge und die Schnittmenge der beiden Mengen zurück:

HashSet set0 = HashSet.rangeClosed(1,5);
HashSet set1 = HashSet.rangeClosed(3, 6);

assertEquals(set0.union(set1), HashSet.rangeClosed(1,6));
assertEquals(set0.diff(set1), HashSet.rangeClosed(1,2));
assertEquals(set0.intersect(set1), HashSet.rangeClosed(3,5));

Wir können auch grundlegende Operationen ausführen, wie das Hinzufügen und Entfernen von Elementen:

HashSet set = HashSet.of("Red", "Green", "Blue");
HashSet newSet = set.add("Yellow");

assertEquals(3, set.size());
assertEquals(4, newSet.size());
assertTrue(newSet.contains("Yellow"));

Die Implementierung vonHashSet wird durch einHash array mapped trie (HAMT) unterstützt, das im Vergleich zu einem normalenHashTable eine überlegene Leistung aufweist und aufgrund seiner Struktur zum Sichern einer persistenten Sammlung geeignet ist.

5.2. TreeSet

Ein unveränderlichesTreeSet ist eine Implementierung derSortedSet-Schnittstelle. Es speichert einSet sortierter Elemente und wird mithilfe von binären Suchbäumen implementiert. Alle Operationen werden in der Zeit O (log n) ausgeführt.

Standardmäßig werden Elemente vonTreeSet in ihrer natürlichen Reihenfolge sortiert.

Erstellen wir einSortedSet in natürlicher Sortierreihenfolge:

SortedSet set = TreeSet.of("Red", "Green", "Blue");
assertEquals("Blue", set.head());

SortedSet intSet = TreeSet.of(1,2,3);
assertEquals(2, intSet.average().get().intValue());

Um Elemente auf benutzerdefinierte Weise zu ordnen, übergeben Sie eineComparator-Instanz, während Sie eineTreeSet. erstellen. Wir können auch eine Zeichenfolge aus den festgelegten Elementen generieren:

SortedSet reversedSet
  = TreeSet.of(Comparator.reverseOrder(), "Green", "Red", "Blue");
assertEquals("Red", reversedSet.head());

String str = reversedSet.mkString(" and ");
assertEquals("Red and Green and Blue", str);

5.3. BitSet

Vavr-Sammlungen enthalten auch eine unveränderlicheBitSet-Implementierung. Die SchnittstelleBitSeterweitert die SchnittstelleSortedSet. BitSet kann mit statischen Methoden inBitSet.Builder instanziiert werden.

Wie bei anderen Implementierungen der Datenstruktur vonSetkönnen mitBitSet keine doppelten Einträge zum Satz hinzugefügt werden.

Es erbt Manipulationsmethoden von derTraversable-Schnittstelle. Beachten Sie, dass es sich vonjava.util.BitSet in der Standard-Java-Bibliothek unterscheidet. Die Daten vonBitSetdürfen keine Werte vonStringenthalten.

Lassen Sie uns sehen, wie Sie eineBitSet-Instanz mit der Factory-Methodeof() erstellen:

BitSet bitSet = BitSet.of(1,2,3,4,5,6,7,8);
BitSet bitSet1 = bitSet.takeUntil(i -> i > 4);
assertEquals(bitSet1.size(), 4);

Wir verwendentakeUntil(), um die ersten vier Elemente vonBitSet. auszuwählen. Die Operation hat eine neue Instanz zurückgegeben. Beachten Sie, dasstakeUntil() in der SchnittstelleTraversable definiert ist, die eine übergeordnete Schnittstelle vonBitSet. ist

Andere oben gezeigte Methoden und Operationen, die in derTraversable-Schnittstelle definiert sind, gelten auch fürBitSet.

6. Map

Eine Map ist eine Schlüsselwert-Datenstruktur. Map von Vavr ist unveränderlich und hat Implementierungen fürHashMap,TreeMap undLinkedHashMap.

Im Allgemeinen lassen Kartenverträge keine doppelten Schlüssel zu, obwohl möglicherweise doppelte Werte verschiedenen Schlüsseln zugeordnet sind.

6.1. HashMap

AHashMap ist eine Implementierung einer unveränderlichenMap-Schnittstelle. Es speichert Schlüssel-Wert-Paare unter Verwendung des Hash-Codes der Schlüssel.

Mapvon Vavr verwendetTuple2, um Schlüssel-Wert-Paare anstelle eines herkömmlichenEntry-Typs darzustellen:

Map> map = List.rangeClosed(0, 10)
  .groupBy(i -> i % 2);

assertEquals(2, map.size());
assertEquals(6, map.get(0).get().size());
assertEquals(5, map.get(1).get().size());

Ähnlich wie beiHashSet wird die Implementierung vonHashMapdurch einen Hash-Array-Mapping-Trie (HAMT) unterstützt, was zu einer konstanten Zeit für fast alle Operationen führt.

Wir können Karteneinträge nach Schlüsseln mit der MethodefilterKeys() oder nach Werten mit der MethodefilterValues()filtern. Beide Methoden akzeptieren einPredicate als Argument:

Map map1
  = HashMap.of("key1", "val1", "key2", "val2", "key3", "val3");

Map fMap
  = map1.filterKeys(k -> k.contains("1") || k.contains("2"));
assertFalse(fMap.containsKey("key3"));

Map fMap2
  = map1.filterValues(v -> v.contains("3"));
assertEquals(fMap2.size(), 1);
assertTrue(fMap2.containsValue("val3"));

Wir können Karteneinträge auch mit der Methodemap()transformieren. Transformieren wir zum Beispielmap1 inMap<String, Integer>:

Map map2 = map1.map(
  (k, v) -> Tuple.of(k, Integer.valueOf(v.charAt(v.length() - 1) + "")));
assertEquals(map2.get("key1").get().intValue(), 1);

6.2. TreeMap

Ein unveränderlichesTreeMap ist eine Implementierung derSortedMap-Schnittstelle. Ähnlich wie beiTreeSet wird eineComparator-Instanz verwendet, um Elemente vonTreeMap benutzerdefiniert zu sortieren.

Lassen Sie uns die Erstellung einesSortedMap demonstrieren:

SortedMap map
  = TreeMap.of(3, "Three", 2, "Two", 4, "Four", 1, "One");

assertEquals(1, map.keySet().toJavaArray()[0]);
assertEquals("Four", map.get(4).get());

Standardmäßig werden Einträge vonTreeMap in der natürlichen Reihenfolge der Schlüssel sortiert. Wir können jedochComparator angeben, die zum Sortieren verwendet werden:

TreeMap treeMap2 =
  TreeMap.of(Comparator.reverseOrder(), 3,"three", 6, "six", 1, "one");
assertEquals(treeMap2.keySet().mkString(), "631");

Wie beiTreeSet wird auch die Implementierung vonTreeMap unter Verwendung eines Baums modelliert, daher haben ihre Operationen die Zeit O (log n). map.get(key) gibtOption zurück, das einen Wert am angegebenen Schlüssel in der Karte umschließt.

7. Interoperabilität mit Java

Die Erfassungs-API ist vollständig mit dem Erfassungsframework von Java kompatibel. Mal sehen, wie das in der Praxis gemacht wird.

7.1. Konvertierung von Java in Vavr

Jede Sammlungsimplementierung in Vavr verfügt über eine statische Factory-MethodeofAll(), diejava.util.Iterable benötigt. Auf diese Weise können wir eine Vavr-Sammlung aus einer Java-Sammlung erstellen. Ebenso nimmt eine andere Factory-MethodeofAll() direkt JavaStream.

So konvertieren Sie ein JavaList in ein unveränderlichesList:

java.util.List javaList = java.util.Arrays.asList(1, 2, 3, 4);
List vavrList = List.ofAll(javaList);

java.util.stream.Stream javaStream = javaList.stream();
Set vavrSet = HashSet.ofAll(javaStream);

Eine weitere nützliche Funktion istcollector(), die in Verbindung mitStream.collect() verwendet werden kann, um eine Vavr-Sammlung zu erhalten:

List vavrList = IntStream.range(1, 10)
  .boxed()
  .filter(i -> i % 2 == 0)
  .collect(List.collector());

assertEquals(4, vavrList.size());
assertEquals(2, vavrList.head().intValue());

7.2. Konvertierung von Vavr nach Java

Die Schnittstelle vonValueverfügt über viele Methoden zum Konvertieren eines Vavr-Typs in einen Java-Typ. Diese Methoden haben das FormattoJavaXXX().

Lassen Sie uns einige Beispiele ansprechen:

Integer[] array = List.of(1, 2, 3)
  .toJavaArray(Integer.class);
assertEquals(3, array.length);

java.util.Map map = List.of("1", "2", "3")
  .toJavaMap(i -> Tuple.of(i, Integer.valueOf(i)));
assertEquals(2, map.get("2").intValue());

Wir können auch Java 8Collectorsverwenden, um Elemente aus Vavr-Sammlungen zu sammeln:

java.util.Set javaSet = List.of(1, 2, 3)
  .collect(Collectors.toSet());

assertEquals(3, javaSet.size());
assertEquals(1, javaSet.toArray()[0]);

7.3. Java-Sammlungsansichten

Alternativ bietet die Bibliothek so genannte Sammlungsansichten, die bei der Konvertierung in Java-Sammlungen eine bessere Leistung erzielen. Die Konvertierungsmethoden aus dem vorherigen Abschnitt durchlaufen alle Elemente, um eine Java-Sammlung zu erstellen.

Views hingegen implementieren Java-Standardschnittstellen und delegieren Methodenaufrufe an die zugrunde liegende Vavr-Auflistung.

Zum jetzigen Zeitpunkt wird nur die AnsichtListunterstützt. Jede sequentielle Sammlung verfügt über zwei Methoden, eine zum Erstellen einer unveränderlichen Ansicht und eine andere für eine veränderbare Ansicht.

Das Aufrufen von Mutator-Methoden in unveränderlicher Ansicht führt zu einemUnsupportedOperationException.

Schauen wir uns ein Beispiel an:

@Test(expected = UnsupportedOperationException.class)
public void givenVavrList_whenViewConverted_thenException() {
    java.util.List javaList = List.of(1, 2, 3)
      .asJava();

    assertEquals(3, javaList.get(2).intValue());
    javaList.add(4);
}

So erstellen Sie eine unveränderliche Ansicht:

java.util.List javaList = List.of(1, 2, 3)
  .asJavaMutable();
javaList.add(4);

assertEquals(4, javaList.get(3).intValue());

8. Fazit

In diesem Tutorial haben wir verschiedene funktionale Datenstrukturen kennengelernt, die von der Collection-API von Vavr bereitgestellt werden. Es gibt nützlichere und produktivere API-Methoden in den Vavr-SammlungenJavaDoc unduser guide.

Schließlich ist zu beachten, dass die Bibliothek auchTry,Option,Either undFuture definiert, die dieValue-Schnittstelle erweitern und infolgedessen Java implementieren Iterable Schnittstelle. Dies impliziert, dass sie sich in bestimmten Situationen als Sammlung verhalten können.

Den vollständigen Quellcode für alle Beispiele in diesem Artikel finden Sie unterover on Github.