VAVR (früher bekannt als Javaslang) ist eine gemeinnützige Funktionsbibliothek für Java 8+. Es ermöglicht Ihnen das Schreiben von funktionalem Scala-ähnlichem Code in Java und dient dazu, die Codemenge zu reduzieren und die Qualität zu verbessern.
Bibliotheksseite .
Unter dem Schnitt befindet sich eine Übersetzung eines Artikels, der Informationen zur
Vavr Collections-API systematisiert.
Übersetzt von
@middle_javaLetzter geänderter Originalartikel: 15. August 2019
1. Übersicht
Die Vavr-Bibliothek, früher als Javaslang bekannt, ist eine funktionale Bibliothek für Java. In diesem Artikel untersuchen wir die leistungsstarke Sammlungs-API.
Weitere Informationen zu dieser Bibliothek finden Sie in
diesem Artikel .
2. Persistente Sammlungen
Wenn eine persistente Sammlung geändert wird, wird eine neue Version der Sammlung erstellt, ohne die aktuelle Version zu ändern.
Die Unterstützung mehrerer Versionen derselben Sammlung kann zu einer ineffizienten Nutzung von CPU und Speicher führen. Die Vavr-Sammlungsbibliothek überwindet dies jedoch, indem sie die Datenstruktur zwischen verschiedenen Versionen der Sammlung teilt.
Dies unterscheidet sich grundlegend von
unmodifiableCollection()
von der Java-Dienstprogrammklasse
Collections
, die lediglich einen Wrapper für die Basissammlung bereitstellt.
Beim Versuch, eine solche Sammlung zu ändern, wird
UnsupportedOperationException
anstatt eine neue Version zu erstellen. Darüber hinaus ist die Basissammlung durch eine direkte Verknüpfung weiterhin veränderbar.
3. Durchfahrbar
Traversable
ist der Basistyp aller Vavr-Sammlungen. Diese Schnittstelle definiert Methoden, die allen Datenstrukturen gemeinsam sind.
Es bietet einige nützliche Standardmethoden wie
size()
,
get()
,
filter()
,
isEmpty()
und andere, die von
isEmpty()
geerbt werden.
Wir erkunden die Sammlungsbibliothek weiter.
4. Seq
Beginnen wir mit den Sequenzen.
Die
Seq
Schnittstelle ist eine sequentielle Datenstruktur. Dies ist die übergeordnete Schnittstelle für
List
,
Stream
,
Queue
,
Array
,
Vector
und
CharSeq
. Alle diese Datenstrukturen haben ihre eigenen einzigartigen Eigenschaften, die wir unten diskutieren werden.
4.1. Liste
List
ist eine energetisch berechnete (eifrig evaluierte Operation, sobald die Werte ihrer Operanden bekannt werden), eine Folge von Elementen, die die
LinearSeq
Schnittstelle erweitern.
Persistente
List
rekursiv mit
Kopf und
Schwanz erstellt :
- Der Kopf ist das erste Element
- Schwanz - eine Liste mit den verbleibenden Elementen (diese Liste besteht auch aus Kopf und Schwanz)
Die
List
API enthält statische Factory-Methoden, mit denen Sie eine
List
erstellen können. Mit
of()
Methode static
of()
können Sie eine Instanz von
List
aus einem oder mehreren Objekten erstellen.
Sie können auch die statische Methode
empty()
verwenden, um eine leere
List
zu erstellen, und die Methode
ofAll()
, um eine
List
vom Typ
Iterable
zu erstellen:
List < String > list = List.of( "Java", "PHP", "Jquery", "JavaScript", "JShell", "JAVA");
Schauen wir uns einige Beispiele für Listenmanipulationen an.
Wir können die
drop()
-Methode und ihre Varianten verwenden, um die ersten
N
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)
entfernt
n
Elemente aus der Liste, beginnend mit dem ersten Element, während
dropRight()
dasselbe tut, beginnend mit dem letzten Element in der Liste.
dropUntil()
entfernt die Elemente aus der Liste, bis das Prädikat
true
, während
dropWhile()
die Elemente entfernt, bis das Prädikat
true
.
Es gibt auch die
dropRightWhile()
und
dropRightUntil()
, mit denen Elemente von rechts entfernt entfernt werden.
Als nächstes wird
take(int n)
verwendet, um Elemente aus der Liste abzurufen. Es nimmt
n
Elemente aus der Liste und stoppt dann. Es gibt auch
takeRight(int n)
, das Elemente vom Ende der Liste übernimmt:
List list5 = list.take(1); assertEquals(list5.single(), "Java"); List list6 = list.takeRight(1); assertEquals(list5.single(), "Java"); List list7 = list.takeUntil(s - > s.length() > 6); assertEquals(list3.size(), 3);
Schließlich nimmt
takeUntil()
Elemente aus der Liste, bis das Prädikat
true
. Es gibt eine Variante von
takeWhile()
, die auch ein Prädikatargument
takeWhile()
.
Darüber hinaus verfügt die API über andere nützliche Methoden, z. B. sogar
distinct()
, das eine Liste von Elementen mit gelöschten Duplikaten zurückgibt, sowie
distinctBy()
, das
Comparator
akzeptiert, um die Gleichheit zu bestimmen.
Es ist sehr interessant, dass es auch
intersperse()
, das ein Element zwischen jedes Element der Liste einfügt. Dies kann für Operationen mit
String
sehr praktisch sein:
List list8 = list .distinctBy((s1, s2) - > s1.startsWith(s2.charAt(0) + "") ? 0 : 1); assertEquals(list3.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 die Liste in Kategorien aufteilen? Und dafür gibt es eine API:
Iterator < List < String >> iterator = list.grouped(2); assertEquals(iterator.head().size(), 2); Map < Boolean, List < String >> 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);
Die
group(int n)
-Methode teilt
List
in Gruppen von jeweils
n
Elementen auf. Die
groupdBy()
-Methode verwendet eine
Function
, die die Logik zum Aufteilen der Liste enthält, und gibt eine
Map
mit zwei Elementen zurück:
true
und
false
.
Der
true
Schlüssel wird der
List
Elemente zugeordnet, die die in
Function
angegebene Bedingung erfüllen. Der
false
Schlüssel wird der
List
Elemente zugeordnet, die diese Bedingung nicht erfüllen.
Wie erwartet ändert sich beim Ändern der
List
die ursprüngliche
List
nicht. Stattdessen
List
immer die neue Version von
List
zurückgegeben.
Wir können auch mit
List
interagieren, indem wir die Semantik des Stapels verwenden und Elemente nach dem LIFO-Prinzip (Last In, First Out) extrahieren. In diesem Sinne gibt es API-Methoden wie
peek()
,
pop()
und
push()
, um den Stapel zu manipulieren:
List < Integer > intList = List.empty(); List < Integer > intList1 = intList.pushAll(List.rangeClosed(5, 10)); assertEquals(intList1.peek(), Integer.valueOf(10)); List intList2 = intList1.pop(); assertEquals(intList2.size(), (intList1.size() - 1));
Mit der Funktion
pushAll()
wird ein Bereich von Ganzzahlen in den Stapel
pushAll()
, und mit der Funktion
pushAll()
wird das
pushAll()
des Stapels abgerufen. Es gibt auch eine
peekOption()
-Methode, mit der das Ergebnis in ein
Option
Objekt eingeschlossen werden kann.
Es gibt andere interessante und wirklich nützliche Methoden in der
List
Oberfläche, die in
Java-Dokumenten gründlich dokumentiert sind.
4.2. Warteschlange
In der unveränderlichen
Queue
werden Elemente
Queue
, sodass Sie sie nach dem FIFO-Prinzip abrufen können (first in, first out).
Queue
besteht aus zwei verknüpften Listen: der vorderen und der hinteren
List
. Die vordere
List
enthält Elemente, die aus der Warteschlange entfernt wurden, und die hintere
List
enthält die Elemente in der Warteschlange.
Auf diese Weise können Sie die Operationen zum Einreihen und Entfernen aus der Warteschlange auf die Komplexität
O (1) setzen . Wenn die
List
in der vorderen
List
endet, wenn sie aus der Warteschlange entfernt wird, wird die hintere
List
umgekehrt und zur neuen vorderen
List
.
Erstellen wir eine Warteschlange:
Queue < Integer > queue = Queue.of(1, 2); Queue < Integer > secondQueue = queue.enqueueAll(List.of(4, 5)); assertEquals(3, queue.size()); assertEquals(5, secondQueue.size()); Tuple2 < Integer, Queue < Integer >> result = secondQueue.dequeue(); assertEquals(Integer.valueOf(1), result._1); Queue < Integer > tailQueue = result._2; assertFalse(tailQueue.contains(secondQueue.get(0)));
Die Funktion
dequeue()
entfernt das head-Element aus der
Queue
und gibt
Tuple2<T, Q>
. Das erste Element des Tupels ist das aus der Warteschlange entfernte Kopfelement, das zweite Element des Tupels sind die verbleibenden
Queue
.
Wir können die
combination(n)
, um alle möglichen
N
Kombinationen von Elementen in der
Queue
:
Queue < Queue < Integer >> queue1 = queue.combinations(2); assertEquals(queue1.get(2).toCharSeq(), CharSeq.of("23"));
Auch hier ändert sich die ursprüngliche
Queue
beim Hinzufügen / Entfernen von Elementen zur Warteschlange nicht.
4.3. Stream
Stream
ist eine Implementierung einer träge verknüpften Liste, die sich erheblich von
java.util.stream
. Im Gegensatz zu
java.util.stream
speichert
Stream
Vavr Daten und berechnet nachfolgende Elemente träge.
Angenommen, wir haben
Stream
Ganzzahlen:
Stream < Integer > s = Stream.of(2, 1, 3, 4);
Beim Drucken des Ergebnisses von
s.toString()
in der Konsole wird nur
Stream (2,?) Angezeigt. Dies bedeutet, dass nur das
Stream
Kopfelement berechnet wurde, die Endelemente jedoch nicht.
s.get(3)
Sie
s.get(3)
und dann das Ergebnis von
s.tail()
anzeigen, wird
Stream (1, 3, 4 s.tail()
. Im Gegenteil, wenn Sie nicht zuerst
s.get(3)
aufrufen,
s.get(3)
Stream
das letzte Element berechnet, ist nur
Stream (1 s.tail()
) Das Ergebnis von
s.tail()
) . Dies bedeutet, dass nur das erste Endelement berechnet wurde.
Dieses Verhalten kann die Leistung verbessern und ermöglicht die Verwendung von
Stream
zur Darstellung von Sequenzen, die (theoretisch) unendlich lang sind.
Stream
in Vavr ist unveränderlich und kann
Empty
oder
Cons
.
Cons
bestehen aus dem Kopfelement und dem träge berechneten Schwanz des
Stream
. Im Gegensatz zu
List
speichert
Stream
das head-Element im Speicher. Schwanzelemente werden nach Bedarf berechnet.
Erstellen wir einen
Stream
mit 10 positiven Ganzzahlen und berechnen die Summe der geraden Zahlen:
Stream < Integer > 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
Stream
API von Java 8 ist
Stream
in Vavr eine Datenstruktur zum Speichern einer Folge von Elementen.
Daher verfügt es über Methoden wie
get()
,
append()
,
insert()
und andere zum Bearbeiten seiner Elemente.
drop()
,
distinct()
und einige andere zuvor diskutierte Methoden sind ebenfalls verfügbar.
Lassen Sie uns abschließend
tabulate()
in
Stream
demonstrieren. Diese Methode gibt einen
Stream
Länge
n
, der Elemente enthält, die das Ergebnis der Anwendung der Funktion sind:
Stream < Integer > s1 = Stream.tabulate(5, (i) - > i + 1); assertEquals(s1.get(2).intValue(), 3);
Wir können auch
zip()
, um einen
Stream
aus
Tuple2<Integer, Integer>
zu erstellen, der Elemente enthält, die durch Kombinieren von zwei
Stream
:
Stream < Integer > s = Stream.of(2, 1, 3, 4); Stream < Tuple2 < Integer, Integer >> s2 = s.zip(List.of(7, 8, 9)); Tuple2 < Integer, Integer > t1 = s2.get(0); assertEquals(t1._1().intValue(), 2); assertEquals(t1._2().intValue(), 7);
4.4. Array
Array
ist eine unveränderliche indizierte Sequenz, die einen effizienten Direktzugriff ermöglicht. Es basiert auf einem Java-
Array von Objekten. Im Wesentlichen ist dies ein
Traversable
Wrapper für ein Array von Objekten vom Typ
T
Sie können eine Instanz von
Array
mit der statischen Methode
of()
erstellen. Darüber hinaus können Sie mit den statischen Methoden
range()
und
rangeBy()
eine Reihe von Elementen erstellen. Die
rangeBy()
-Methode verfügt über einen dritten Parameter, mit dem Sie den Schritt bestimmen können.
Die Methoden
range()
und
rangeBy()
erstellen Elemente, beginnend nur vom Anfangswert bis zum Endwert minus eins. Wenn wir den Endwert
rangeClosed()
, können wir
rangeClosed()
oder
rangeClosedBy()
:
Array < Integer > rArray = Array.range(1, 5); assertFalse(rArray.contains(5)); Array < Integer > rArray2 = Array.rangeClosed(1, 5); assertTrue(rArray2.contains(5)); Array < Integer > rArray3 = Array.rangeClosedBy(1, 6, 2); assertEquals(list3.size(), 3);
Lassen Sie uns mit den Elementen anhand des Index arbeiten:
Array < Integer > intArray = Array.of(1, 2, 3); Array < Integer > newArray = intArray.removeAt(1); assertEquals(3, intArray.size()); assertEquals(2, newArray.size()); assertEquals(3, newArray.get(1).intValue()); Array < Integer > array2 = intArray.replace(1, 5); assertEquals(s1.get(0).intValue(), 5);
4.5. Vektor
Vector
ist eine Kreuzung zwischen
Array
und
List
, die eine weitere indizierte Folge von Elementen bereitstellt und sowohl den wahlfreien Zugriff als auch die Änderung in konstanter Zeit ermöglicht:
Vector < Integer > intVector = Vector.range(1, 5); Vector < Integer > 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 zur Darstellung einer Folge primitiver Zeichen. Im Wesentlichen ist dies ein Wrapper für
String
mit zusätzlichen Erfassungsoperationen.
Um
CharSeq
zu erstellen, müssen Sie Folgendes tun.
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. Stellen Sie ein
In diesem Abschnitt werden die verschiedenen Implementierungen von
Set
in der Sammlungsbibliothek erläutert. Ein einzigartiges Merkmal der
Set
Datenstruktur ist, dass keine doppelten Werte zulässig sind.
Es gibt verschiedene Implementierungen von
Set
. Das wichtigste ist
HashSet
.
TreeSet
erlaubt keine doppelten Elemente und kann sortiert werden.
LinkedHashSet
die
LinkedHashSet
der Elemente bei.
Schauen wir uns diese Implementierungen nacheinander genauer an.
5.1. Hashset
HashSet
verfügt über statische Factory-Methoden zum Erstellen neuer Instanzen. Einige davon haben wir weiter oben in diesem Artikel untersucht, zum Beispiel
of()
,
ofAll()
und Variationen der
range()
-Methoden.
Die Differenz zwischen den beiden
Mengen kann mit der
diff()
-Methode ermittelt werden. Außerdem geben die Methoden
union()
und
intersect()
die Vereinigung und den Schnittpunkt zweier
Mengen zurück :
HashSet < Integer > set0 = HashSet.rangeClosed(1, 5); HashSet < Integer > set0 = HashSet.rangeClosed(1, 5); 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, z. B. das Hinzufügen und Entfernen von Elementen:
HashSet < String > set = HashSet.of("Red", "Green", "Blue"); HashSet < String > newSet = set.add("Yellow"); assertEquals(3, set.size()); assertEquals(4, newSet.size()); assertTrue(newSet.contains("Yellow"));
Die
HashSet
Implementierung basiert auf dem
Hash Array Mapped Trie (HAMT) , das im Vergleich zur üblichen
HashTable
eine überlegene Leistung
HashTable
und aufgrund seiner Struktur für die Unterstützung persistenter Sammlungen geeignet ist.
5.2. Baumset
TreeSet
ist eine Implementierung der
SortedSet
Schnittstelle. Es speichert eine Reihe sortierter Elemente und wird mithilfe von binären Suchbäumen implementiert. Alle seine Operationen werden während der
O (log n) Zeit ausgeführt .
Standardmäßig werden
TreeSet
Elemente in ihrer natürlichen Reihenfolge sortiert.
Erstellen wir ein
SortedSet
mit einer natürlichen Sortierreihenfolge:
SortedSet < String > set = TreeSet.of("Red", "Green", "Blue"); assertEquals("Blue", set.head()); SortedSet < Integer > intSet = TreeSet.of(1, 2, 3); assertEquals(2, intSet.average().get().intValue());
TreeSet
beim Erstellen des
TreeSet
eine
Comparator
Instanz, um Elemente auf benutzerdefinierte Weise
TreeSet
. Sie können eine Zeichenfolge auch aus einer Reihe von Elementen erstellen:
SortedSet < String > 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 haben auch eine unveränderliche
BitSet
Implementierung. Die
BitSet
Schnittstelle erweitert die
SortedSet
Schnittstelle.
BitSet
kann mit statischen Methoden in
BitSet.Builder
.
Wie bei anderen Implementierungen der
Set
Datenstruktur können Sie mit
BitSet
keine doppelten Datensätze zu einem Set hinzufügen.
Es erbt Manipulationsmethoden von der
Traversable
Schnittstelle. Beachten Sie, dass es sich von
java.util.BitSet
von der Standard-Java-Bibliothek unterscheidet.
BitSet
Daten dürfen keine
String
Werte enthalten.
Erstellen Sie eine Instanz von
BitSet
mit der Factory-Methode
of()
:
BitSet < Integer > bitSet = BitSet.of(1, 2, 3, 4, 5, 6, 7, 8); BitSet < Integer > bitSet1 = bitSet.takeUntil(i - > i > 4); assertEquals(list3.size(), 4);
Um die ersten vier
BitSet
Elemente auszuwählen
BitSet
wir den Befehl
takeUntil()
. Die Operation hat eine neue Instanz zurückgegeben. Beachten Sie, dass die
takeUntil()
-Methode in der
Traversable
Schnittstelle definiert ist, die die übergeordnete Schnittstelle für
BitSet
.
Andere oben in der
Traversable
Schnittstelle definierte Methoden und Operationen gelten auch für
BitSet
.
6. Karte
Map
ist eine Schlüsselwertdatenstruktur.
Map
in Vavr ist unveränderlich und verfügt über Implementierungen für
HashMap
,
TreeMap
und
LinkedHashMap
.
In der Regel lassen
Kartenverträge keine doppelten Schlüssel zu, während doppelte Werte, die verschiedenen Schlüsseln zugeordnet sind, möglicherweise doppelt vorhanden sind.
6.1. Hashmap
HashMap
ist eine Implementierung der unveränderlichen
Map
Schnittstelle. Es speichert Schlüssel-Wert-Paare unter Verwendung eines Hash von Schlüsseln.
Map
in Vavr verwendet
Tuple2
, um Schlüssel-Wert-Paare anstelle des herkömmlichen Eintragstyps
Tuple2
:
Map < Integer, List < Integer >> 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());
Wie bei
HashSet
basiert die Implementierung von
HashMap
auf dem
Hash Array Mapped Trie (HAMT) , was zu einer konstanten Zeit für fast alle Operationen führt.
filterKeys()
können mit der Methode
filterKeys()
nach Schlüsseln oder mit der Methode
filterKeys()
nach Werten
filterValues()
werden. Beide Methoden verwenden
Predicate
als Argument:
Map < String, String > map1 = HashMap.of("key1", "val1", "key2", "val2", "key3", "val3"); Map < String, String > fMap = map1.filterKeys(k - > k.contains("1") || k.contains("2")); assertFalse(fMap.containsKey("key3")); Map < String, String > map1 = map1.filterValues(v - > v.contains("3")); assertEquals(list3.size(), 1); assertTrue(fMap2.containsValue("val3"));
Sie können
Kartenelemente auch mit der
map()
-Methode transformieren. Konvertieren
wir beispielsweise
map1 in
Map<String, Integer>
:
Map < String, Integer > map2 = map1.map( (k, v) - > Tuple.of(k, Integer.valueOf(v.charAt(v.length() - 1) + ""))); assertEquals(map2.get("key1").get().intValue(), 1);
6.2. Baumkarte
TreeMap
ist eine Implementierung der
SortedMap
Schnittstelle. Wie bei
TreeSet
wird eine benutzerdefinierte Instanz von
Comparator
verwendet, um die Sortierung von
TreeMap
Elementen
TreeMap
.
SortedMap
die Erstellung von
SortedMap
:
SortedMap < Integer, String > 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
TreeMap
Einträge in der Reihenfolge der natürlichen Schlüssel sortiert. Sie können jedoch den
Comparator
angeben, der zum Sortieren verwendet werden soll:
TreeMap < Integer, String > treeMap2 = TreeMap.of(Comparator.reverseOrder(), 3, "three", 6, "six", 1, "one"); assertEquals(treeMap2.keySet().mkString(), "631");
Wie im Fall von
TreeSet
wird auch die
TreeMap
Implementierung unter Verwendung des Baums erstellt, daher haben ihre Operationen die Zeit
O (log n) . Die
map.get(key)
-Methode gibt
Option
, die den Wert des angegebenen
Map- Schlüssels enthält.
7. Java-Kompatibilität
Die Vavr Collection-API ist vollständig kompatibel mit dem Java Collection Framework. Mal sehen, wie das in der Praxis gemacht wird.
7.1. Konvertieren Sie von Java nach Vavr
Jede Auflistungsimplementierung in Vavr verfügt über eine statische Factory
ofAll()
-Methode, die
java.util.Iterable
akzeptiert. Auf diese Weise können Sie eine
Vavr- Sammlung aus einer
Java- Sammlung erstellen. In ähnlicher Weise akzeptiert eine andere
ofAll()
Factory-Methode direkt Java
Stream
.
So konvertieren Sie eine Java-
List
in eine unveränderliche
List
:
java.util.List < Integer > javaList = java.util.Arrays.asList(1, 2, 3, 4); List < Integer > vavrList = List.ofAll(javaList); java.util.stream.Stream < Integer > javaStream = javaList.stream(); Set < Integer > vavrSet = HashSet.ofAll(javaStream);
Eine weitere nützliche Funktion ist
collector()
, die in Verbindung mit
Stream.collect()
, um die Vavr-Sammlung abzurufen:
List < Integer > 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. Konvertieren Sie von Vavr nach Java
Die
Value
Schnittstelle verfügt über viele Methoden zum Konvertieren von einem
Vavr- Typ in einen
Java- Typ. Diese Methoden haben das Format
toJavaXXX()
.
Betrachten Sie einige Beispiele:
Integer[] array = List.of(1, 2, 3) .toJavaArray(Integer.class); assertEquals(3, array.length); java.util.Map < String, Integer > 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 8
Collectors
, um Objekte aus Vavr-Sammlungen zu sammeln:
java.util.Set < Integer > javaSet = List.of(1, 2, 3) .collect(Collectors.toSet()); assertEquals(3, javaSet.size()); assertEquals(1, javaSet.toArray()[0]);
7.3. Java-Sammlungsansichten
Darüber hinaus bietet die Bibliothek sogenannte
Sammlungsansichten , die bei der Konvertierung in Java-Sammlungen am besten funktionieren. Die Transformationsmethoden im vorherigen Abschnitt durchlaufen alle Elemente, um eine Java-Sammlung zu erstellen.
Ansichten hingegen implementieren Standard-Java-Schnittstellen und delegieren Methodenaufrufe an die Vavr-Basissammlung.
Zum Zeitpunkt dieses Schreibens wird nur die
List
unterstützt. Jede sequentielle Sammlung verfügt über zwei Methoden: eine zum Erstellen einer unveränderlichen Darstellung, die andere zum Ändern.
Das Aufrufen von Methoden zum Ändern einer unveränderlichen Ansicht
UnsupportedOperationException
.
Schauen wir uns ein Beispiel an:
@Test(expected = UnsupportedOperationException.class) public void givenVavrList_whenViewConverted_thenException() { java.util.List < Integer > 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 < Integer > javaList = List.of(1, 2, 3) .asJavaMutable(); javaList.add(4); assertEquals(4, javaList.get(3).intValue());
8. Schlussfolgerungen
In diesem Tutorial haben wir die verschiedenen funktionalen Datenstrukturen kennengelernt, die von der Vavr Collections-API bereitgestellt werden. Es gibt auch nützliche und produktive API-Methoden, die im
Java-Dokument und
im Vavr Collections-
Benutzerhandbuch enthalten sind .
Schließlich ist zu beachten, dass die Bibliothek auch
Try
,
Option
,
Either
und
Future
, wodurch die
Value
Schnittstelle erweitert und infolgedessen die Java
Iterable
Schnittstelle
Iterable
wird. Dies bedeutet, dass sie sich in einigen Situationen wie Sammlungen verhalten können.
Den vollständigen Quellcode für alle Beispiele in diesem Artikel finden Sie auf
Github .
Zusätzliche Materialien:
habr.com/de/post/421839www.baeldung.com/vavrÜbersetzt von
@middle_java