Arbeiten mit Karten mithilfe von Streams

1. Einleitung

In diesem Tutorial werden einige Beispiele für die Verwendung von Java Streams erläutertmit Map s arbeiten. Es ist erwähnenswert, dass einige dieser Übungen eine bidirektionale Verwendung gelöst werden könnten Map - Datenstruktur, aber wir sind hier in einem funktionalen Ansatz interessiert.

Zunächst erklären wir die Grundidee, mit der wir mit Maps und Streams arbeiten . Anschließend stellen wir einige verschiedene Probleme im Zusammenhang mit Karten und ihren konkreten Lösungen unter Verwendung von Streams vor .

2. Grundidee

Das Wichtigste ist, dass Streams Sequenzen von Elementen sind, die leicht aus einer Sammlung abgerufen werden können .

Karten haben eine andere Struktur, mit einer Zuordnung von Tasten zu Werten, ohne Reihenfolge. Dies bedeutet nicht, dass wir eine Map- Struktur nicht in verschiedene Sequenzen konvertieren können, sodass wir auf natürliche Weise mit der Stream-API arbeiten können.

Lassen Sie uns sehen, wie Sie verschiedene Sammlungen von einer Karte erhalten , die wir dann in einen Stream schwenken können :

Map someMap = new HashMap();

Wir können eine Reihe von Schlüssel-Wert-Paaren erhalten:

Set
    
      entries = someMap.entrySet();
    

Wir können auch den mit der Karte verknüpften Schlüsselsatz erhalten :

Set keySet = someMap.keySet();

Oder wir könnten direkt mit den Werten arbeiten:

Collection values = someMap.values();

Diese geben uns jeweils einen Einstiegspunkt, um diese Sammlungen zu verarbeiten, indem wir Streams von ihnen erhalten:

Stream
    
      entriesStream = entries.stream(); Stream valuesStream = values.stream(); Stream keysStream = keySet.stream();
    

3. Wie Sie einen Map ‚s Tasten Mit Stream - s

3.1. Eingabedaten

Nehmen wir an, wir haben eine Karte :

Map books = new HashMap(); books.put( "978-0201633610", "Design patterns : elements of reusable object-oriented software"); books.put( "978-1617291999", "Java 8 in Action: Lambdas, Streams, and functional-style programming"); books.put("978-0134685991", "Effective Java");

Wir sind daran interessiert, die ISBN für das Buch mit dem Titel „Effective Java“ zu finden.

3.2. Ein Match abrufen

Da der Buchtitel in unserer Karte nicht vorhanden sein konnte, möchten wir darauf hinweisen können, dass keine ISBN dafür zugeordnet ist. Wir können eine Option verwenden , um Folgendes auszudrücken :

Nehmen wir für dieses Beispiel an, dass wir an einem Schlüssel für ein Buch interessiert sind, das diesem Titel entspricht:

Optional optionalIsbn = books.entrySet().stream() .filter(e -> "Effective Java".equals(e.getValue())) .map(Map.Entry::getKey) .findFirst(); assertEquals("978-0134685991", optionalIsbn.get());

Lassen Sie uns den Code analysieren. Zuerst erhalten wir das entrySet von der Karte , wie wir zuvor gesehen haben.

Wir möchten nur die Einträge mit "Effective Java" als Titel betrachten, daher wird die erste Zwischenoperation ein Filter sein.

Wir interessieren uns nicht für den gesamten Karteneintrag , sondern für den Schlüssel jedes Eintrags. Die nächste verkettete Zwischenoperation macht genau das: Es ist eine Kartenoperation , die einen neuen Stream als Ausgabe generiert, der nur die Schlüssel für die Einträge enthält, die mit dem gesuchten Titel übereinstimmen.

Da wir nur ein Ergebnis wünschen, können wir die Terminaloperation findFirst () anwenden , die den Anfangswert im Stream als optionales Objekt bereitstellt .

Sehen wir uns einen Fall an, in dem kein Titel existiert:

Optional optionalIsbn = books.entrySet().stream() .filter(e -> "Non Existent Title".equals(e.getValue())) .map(Map.Entry::getKey).findFirst(); assertEquals(false, optionalIsbn.isPresent());

3.3. Mehrere Ergebnisse abrufen

Lassen Sie uns das Problem jetzt ändern, um zu sehen, wie wir mit der Rückgabe mehrerer Ergebnisse anstelle von einem umgehen können.

Um mehrere Ergebnisse zurückzugeben, fügen wir unserer Karte das folgende Buch hinzu :

books.put("978-0321356680", "Effective Java: Second Edition"); 

Wenn wir nun nach allen Büchern suchen , die mit „Effective Java“ beginnen, erhalten wir mehr als ein Ergebnis zurück:

List isbnCodes = books.entrySet().stream() .filter(e -> e.getValue().startsWith("Effective Java")) .map(Map.Entry::getKey) .collect(Collectors.toList()); assertTrue(isbnCodes.contains("978-0321356680")); assertTrue(isbnCodes.contains("978-0134685991"));

Was wir in diesem Fall geschehen ist , die Filterbedingung zu ersetzen , um zu überprüfen , ob der Wert in der Map beginnt mit „Effective Java“ statt für den Vergleich von String Gleichheit.

Dieses Mal sammeln wir die Ergebnisse - anstatt die ersten auszuwählen - und fügen die Übereinstimmungen in eine Liste ein .

4. Wie Sie einen Map ‚s Werten mit Stream - s

Konzentrieren wir uns nun auf ein anderes Problem mit Karten: Anstatt ISBNs basierend auf den Titeln zu erhalten , werden wir versuchen, Titel basierend auf den ISBNs zu erhalten.

Lassen Sie uns das Original verwenden Karte . Wir wollen Titel finden, deren ISBN mit „978-0“ beginnt.

List titles = books.entrySet().stream() .filter(e -> e.getKey().startsWith("978-0")) .map(Map.Entry::getValue) .collect(Collectors.toList()); assertEquals(2, titles.size()); assertTrue(titles.contains( "Design patterns : elements of reusable object-oriented software")); assertTrue(titles.contains("Effective Java"));

Diese Lösung ähnelt den Lösungen für unsere vorherigen Probleme - wir streamen den Eintragssatz und filtern, ordnen ihn zu und sammeln ihn.

Und wie zuvor, wenn wir nur die erste Übereinstimmung zurückgeben wollten, könnten wir nach der map- Methode die findFirst () -Methode aufrufen , anstatt alle Ergebnisse in einer Liste zu sammeln .

5. Schlussfolgerung

Wir haben gezeigt, wie eine Karte auf funktionale Weise verarbeitet wird .

Insbesondere haben wir festgestellt, dass die Verarbeitung mit Streams viel einfacher und intuitiver wird , sobald wir auf die Verwendung der zugehörigen Sammlungen zu Map s umsteigen.

Und natürlich finden Sie alle Beispiele im GitHub-Projekt.