Anleitung zu Java 8 forEach

Leitfaden für Java 8 forEach

1. Überblick

Die in Java 8 eingeführteforEach-Schleife bietet Programmiererna new, concise and interesting way for iterating over a collection.

In diesem Artikel erfahren Sie, wie SieforEach mit Sammlungen verwenden, welche Art von Argument erforderlich ist und wie sich diese Schleife von den erweitertenfor-loop unterscheidet.

Wenn Sie einige Konzepte von Java 8 auffrischen müssen, haben wircollection of articles, die Ihnen helfen können.

2. Grundlagen vonforEach

In Java hat dieCollection-SchnittstelleIterable als Superschnittstelle - und ab Java 8 verfügt diese Schnittstelle über eine neue API:

void forEach(Consumer action)

Einfach ausgedrückt bedeutetJavadoc vonforEach, dass es“performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception.” ist

MitforEach können wir also eine Sammlung durchlaufen und für jedes Element eine bestimmte Aktion ausführen, wie für alle anderenIterator.

Zum Beispiel einefor-loop-Version des Iterierens und Druckens vonCollection vonStrings:

for (String name : names) {
    System.out.println(name);
}

Wir können dies mitforEach schreiben als:

names.forEach(name -> {
    System.out.println(name);
});

3. Verwenden derforEach-Methode

Wir verwendenforEach, um eine Sammlung zu durchlaufen und eine bestimmte Aktion für jedes Element auszuführen. The action to be performed is contained in a class that implements the Consumer interface and is passed to forEach as an argument.

DieConsumer-Schnittstelle ista functional interface (eine Schnittstelle mit einer einzelnen abstrakten Methode). Es akzeptiert eine Eingabe und gibt kein Ergebnis zurück.

Hier ist die Definition:

@FunctionalInterface
public interface Consumer {
    void accept(T t);
}

Daher kann jede Implementierung, zum Beispiel ein Verbraucher, der einfach einString druckt:

Consumer printConsumer = new Consumer() {
    public void accept(String name) {
        System.out.println(name);
    };
};

kann als Argument anforEach übergeben werden:

names.forEach(printConsumer);

Dies ist jedoch nicht die einzige Möglichkeit, eine Aktion über einen Verbraucher zu erstellen und die API vonforEachzu verwenden.

Sehen wir uns die drei beliebtesten Methoden an, mit denen wir die MethodeforEachverwenden:

3.1. AnonymConsumer Implementierung

Wir können eine Implementierung derConsumer-Schnittstelle mithilfe einer anonymen Klasse instanziieren und sie dann als Argument auf dieforEach-Methode anwenden:

Consumer printConsumer= new Consumer() {
    public void accept(String name) {
        System.out.println(name);
    }
};
names.forEach(printConsumer);

Dies funktioniert gut, aber wenn wir das obige Beispiel analysieren, werden wir sehen, dass der tatsächlich verwendete Teil der Code in deraccept()-Methode ist.

Obwohl Lambda-Ausdrücke heute die Norm und der einfachere Weg sind, lohnt es sich dennoch zu wissen, wie dieConsumer-Schnittstelle implementiert wird.

3.2. Ein Lambda-Ausdruck

Der Hauptvorteil von Java 8-Funktionsschnittstellen besteht darin, dass wir Lambda-Ausdrücke verwenden können, um sie zu instanziieren und sperrige anonyme Klassenimplementierungen zu vermeiden.

Da die Schnittstelle vonConsumereine funktionale Schnittstelle ist, können wir sie in Lambda in Form von:

(argument) -> { //body }

Daher vereinfacht sich unserprintConsumer zu:

name -> System.out.println(name)

Und wir können es anforEach as übergeben:

names.forEach(name -> System.out.println(name));

Seit der Einführung von Lambda-Ausdrücken in Java 8 ist dies wahrscheinlich die häufigste Methode zur Verwendung der MethodeforEach.

Lambdas haben eine sehr reale Lernkurve. Wenn Sie also anfangen, gehtthis write-up einige bewährte Methoden zum Arbeiten mit der neuen Sprachfunktion durch.

3.3. Eine Methodenreferenz

Wir können anstelle der normalen Lambda-Syntax eine Methodenreferenzsyntax verwenden, bei der bereits eine Methode vorhanden ist, um eine Operation für die Klasse auszuführen:

names.forEach(System.out::println);

4. Arbeiten mitforEach

4.1. Iterieren über aCollection

Alle iterierbaren Elemente vom TypCollection – list, set, queue etc. haben die gleiche Syntax für die Verwendung vonforEach.

Daher, wie wir bereits gesehen haben, Elemente einer Liste durchlaufen:

List names = Arrays.asList("Larry", "Steve", "James");

names.forEach(System.out::println);

Ähnliches gilt für ein Set:

Set uniqueNames = new HashSet<>(Arrays.asList("Larry", "Steve", "James"));

uniqueNames.forEach(System.out::println);

Oder sagen wir für einQueue, das auch einCollection ist:

Queue namesQueue = new ArrayDeque<>(Arrays.asList("Larry", "Steve", "James"));

namesQueue.forEach(System.out::println);

4.2. Iterieren über eine Karte - unter Verwendung derforEach der Karte

Karten sind nichtIterable, aberprovide their own variant of forEach that accepts a*BiConsumer*. 

EinBiConsumer wurde anstelle vonConsumer inforEach von Iterable eingeführt, damit eine Aktion sowohl für den Schlüssel als auch für den Wert vonMap gleichzeitig ausgeführt werden kann.

Erstellen wir einMapmit Einträgen:

Map namesMap = new HashMap<>();
namesMap.put(1, "Larry");
namesMap.put(2, "Steve");
namesMap.put(3, "James");

Lassen Sie uns als Nächstes übernamesMap mitforEach von Map iterieren:

namesMap.forEach((key, value) -> System.out.println(key + " " + value));

Wie wir hier sehen können, haben wirBiConsumer verwendet:

(key, value) -> System.out.println(key + " " + value)

über die Einträge derMap iterieren.

4.3. Iterieren über aMap – by iterating entrySet

Wir können auch dieEntrySet of aMap iterieren, die dieforEach. von Iterable enthalten

Dathe entries of a Map are stored in a Set called EntrySet, we can iterate that using a forEach:

namesMap.entrySet().forEach(entry -> System.out.println(
  entry.getKey() + " " + entry.getValue()));

5. Foreach gegen For-Loop

Von einem einfachen Standpunkt aus bieten beide Schleifen dieselbe Funktionalität - sie durchlaufen Elemente in einer Sammlung.

The main difference between the two of them is that they are different iterators – the enhanced for-loop is an external iterator whereas the new forEach method is an internal one.

5.1. Interner Iterator -forEach

Diese Art von Iterator verwaltet die Iteration im Hintergrund und überlässt es dem Programmierer, nur zu codieren, was mit den Elementen der Auflistung geschehen soll.

Der Iterator verwaltet stattdessen die Iteration und stellt sicher, dass die Elemente einzeln verarbeitet werden.

Sehen wir uns ein Beispiel für einen internen Iterator an:

names.forEach(name -> System.out.println(name));

In der obigen MethodeforEach können wir sehen, dass das angegebene Argument ein Lambda-Ausdruck ist. Dies bedeutet, dass die Methode nurwhat is to be done kennen muss und die gesamte Iterationsarbeit intern erledigt wird.

5.2. Externer Iterator -for-loop

Externe Iteratoren mischen diewhat und diehow, die die Schleife ausführen soll.

Enumerations,Iterators und erweitertefor-loop sind alle externe Iteratoren (erinnern Sie sich an die Methodeniterator(),next() oderhasNext()? ). In all diesen Iteratoren ist es unsere Aufgabe, festzulegen, wie Iterationen durchgeführt werden sollen.

Betrachten Sie diese bekannte Schleife:

for (String name : names) {
    System.out.println(name);
}

Obwohl wir beim Durchlaufen der Liste nicht explizit die MethodenhasNext() odernext() aufrufen, verwendet der zugrunde liegende Code, der diese Iteration zum Funktionieren bringt, diese Methoden. Dies impliziert, dass die Komplexität dieser Operationen vor dem Programmierer verborgen ist, aber immer noch vorhanden ist.

Im Gegensatz zu einem internen Iterator, bei dem die Auflistung die Iteration selbst durchführt, benötigen wir hier externen Code, der jedes Element aus der Auflistung entfernt.

6. Fazit

In diesem Artikel haben wir gezeigt, dass dieforEach-Schleife bequemer ist als die normalenfor-loop.

Wir haben auch gesehen, wie die MethodeforEachfunktioniert und welche Art von Implementierung als Argument empfangen werden kann, um eine Aktion für jedes Element in der Auflistung auszuführen.

Schließlich sind alle in diesem Artikel verwendeten Snippets in unseremGithub-Repository verfügbar.