Java forEach: So funktioniert die forEach-Methode in Java!

    Avatarbild von Perica Glavas
    Perica Glavas

    veröffentlicht am: 22.06.2020
    zuletzt aktualisiert am: 06.02.2023

    Die Java foreach-Methode im Detail

    Mit Java 8 kamen eine Menge neuer Methoden in die Schnittstellen. Unter anderem neue Datums- und Zeit-APIs, Streams, Lambdas und die Java forEach-Methode. Von all diesen neuen Spielzeugen sind die Lambdas wahrscheinlich das meist diskutierte; und das auch aus gutem Grund. Denn die Lambdas machen die funktionale Programmierung in Java erst möglich. Funktionales Programmieren ist ein wichtiges Thema, soll aber nicht unser Thema für diesen Artikel sein. Vielmehr werden wir über forEach-Methode sprechen. Auf gewisse Weise werden wir zwar mit Lambdas und der funktionalen Programmierung in Berührung kommen, konzentrieren uns aber vorerst auf die forEach-Methode konzentrieren.

    Um forEach nicht mit der erweiterten for-Schleife zu verwechseln, ist die forEach-Methode zu der Schnittstelle des „Iterable“ hinzugefügt worden. Wir erinnern uns daran, dass die Iterable-Schnittstelle ein Supertyp für Schnittstellen und Klassen im „Java Collection Framework“(JCF) ist.

    Einführung – Java forEach

    Durch das Hinzufügen der forEach-Methode zu „Iterable“ kann die Methode natürlich auch von allen anderen im „JCF“ verwendet werden. Die forEach-Methode ist als Ersatz bzw. Verbesserung für die äußerst klobigen Schleifenmechanismen von Java entwickelt worden. Die aktualisierte for-Schleife ist grundsätzlich nicht schlecht, da sie gegenüber der traditionellen Schleife schon eine deutliche Verbesserung darstellt. Betrachten wir dafür einmal folgenden Code:

    List<String> namen = Arrays.asList("Alvin","Theodore","Simon");
    
    for (String name : namen) {
      System.out.println(name);
    }

    Wir sehen, dass die Schleife eigentlich garnicht so schlecht aussieht. Es sieht eigentlich relativ sauber aus. Aber schauen wir uns dagegen einmal die Version mit der forEach-Methode an:

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

    Wie wir sehen, ist der Ausdruck deutlich aussagekräftiger. Wenn wir uns noch nicht viel mit funktionaler Programmierung beschäftigt haben, sieht der Ausdruck zunächst komisch aus. Aber dafür können wir uns diesen ja etwas aufschlüsseln.

    Grundsätzlich ist wichtig, dass es sich bei der forEach um keine Anweisung wie bei der for-Schleife oder der erweiterten for-Schleifen handelt, sondern eine Methode, die auf alle Sammelobjekte und Streams angewendet werden kann.

    Der Pfeil-Operator, den wir als „->“ schreiben, wird auch als Lambda-Operator bezeichnet. Dieser ist erforderlich, um den Parameter vom Lambda-Körper zu trennen. Der Lambda-Körper kann entweder ein Ausdruck oder ein gesamter Anweisungsblock sein.

    In unserem forEach-Beispiel steht die Namensvariable (auf der linken Seite des „->“) für jedes Element in der Namen-Liste. Die Print-Funktion auf der rechten Seite des „->“ ist der Lambda-Körper. Er steht in diesem Fall ohne Klammern, da es sich nur um eine Anweisung handelt. Man könnte aber genauso gut auch Klammern nutzen.

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

    Die Elemente der Sammlung (Namen-Liste) sind für den Lambda-Körper zugänglich, deshalb können wir diese in der println()-Funktion nutzen.

    Wir können auch Methodenverweise nutzen, um eine kompakte und einfache Form der Lambda-Ausdrücke zu erhalten. Wenn wir das vorherige Beispiel mit einem Methodenverweis formulieren wollen, sieht dies wie folgt aus:

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

    Ein Methodenverweis kann sich auf drei Typen beziehen:

    1. auf die statische Methode, dir wir gerade verwenden wollen
    2. eine Instanz-Methode
    3. einen Konstruktor

    Nutzung der Java forEach Methode

    Alle Iterablen Typen (d.h. praktisch alle Typen die Sammlungen darstellen) haben die gleiche Syntax für die Verwendung der forEach-Methode.

    Um also über eine Liste von Strings zu iterieren, können wir den folgenden Code verwenden:

    List<String> names = Arrays.asList("Alvin","Theodore","Simon");
    names.forEach(System.out::println);

    Wenn wir ein Set verwenden wollen, funktioniert das ähnlich:

    Set<String> namen = new HashSet<>(Arrays.asList("Alvin", "Theodore", "Simon"));
    namen.forEach(System.out::println);

    Wir können forEach auch mit Maps verwenden, selbst wenn diese eine eigentlich nicht iterierbare Schnittstellen besitzen. Die Map-Schnittstelle bietet deshalb eine ähnliche Implementierung für forEach. Die Lambda-Aktionen können gleichzeitig mit dem Schlüssel und dem Wert der Map ausgeführt werden.

    fruechte.put(1, "Apple");
    fruechte.put(2, "Orange");
    fruechte.put(3, "Banana");
    
    fruechte.forEach((key, value) -> {
      System.out.printf("Schlüssel:%s | Wert:%s\n", key,value);
    });

    Interne und externe Iteratoren im Bezug auf die Java forEach-Methode

    Die for-Schleife und die forEach-Methode lassen sich dadurch unterscheiden, welche Art von Iteratoren sie jeweils verwenden. Die forEach-Methode verwendet einen internen Iterator, während die for-Schleife hingegen einen externen Iterator verwendet.

    Ein Ausdruck, bei dem interne Iteratoren verwendet werden, sieht wie folgt aus:

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

    Jedes Element der Sammlung wird automatisch dem Lambda-Ausdruck (Name) zur Verfügung gestellt. Innerhalb des Lambda-Körpers geht es uns dann nur darum, mit den Daten (den Elementen in der Sammlung) das zu machen, was notwendig ist. Wir müssen nicht angeben, wie wir die Iterationen durchführen wolle. Wir müssen keine Schritte, keine next()- oder hasNext()-Methoden verwenden. Somit haben wir einfach eine Operation an den Daten durchgeführt. Die Iteration wurde automatisch durchgeführt.

    Eine for-Schleife würde wie folgt aussehen:

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

    Selbst wenn wir die hasNext()-, Iterator()- und next()-Methoden in diesem Beispiel nicht sehen, ist es das, was die for-Schleife unsichtbar vor uns macht (sie ist praktisch eine Vereinfachung der Schreibweise). In der Klammer der for-Schleife können wir die Iterationen selbst steuern. Wir können die Schritte dirigieren, da wir einen externen Iterator haben. Im Gegensatz zu einem internen Iterator, bei dem wir uns auf die Methode zur Iteration verlassen müssen, haben wir hier die volle Kontrolle.

    Zusammenfassung

    Die Java forEach-Methode ist eine neue Methode, die allen JCF-Klassen seit Java 8, die Möglichkeit einräumt, übersichtlich und einfach die entsprechende Sammlung zu durchqueren (iterieren). Bei der forEach-Methode wird ein interner Iterator verwendet, der uns im Gegensatz zur herkömmlichen for-Schleife keine Kontrolle über die Iteration gibt. Normalerweise erwartet die forEach-Methode ein Objekt vom Typ der Consumer-Schnittstelle (das ist aber wiederum ein ganz anderes Thema). Vorerst verwenden wir deshalb nur die Lambda-Ausdrücke in Verbindung mit der forEach-Methode.

    😩 Gelangweilt von den Udemy & YouTube-Tutorials?!

    Lerne spielerisch Java und komme deiner gutbezahlten (und an der 🌴 liegenden) Traumkarriere einen Schritt weiter.

    TP Star TP Star TP Star TP Star TP Star

    "Für Leute die gerne Python oder Java lernen wollen ist Codegree klasse. Ist nicht wie bei anderen Konkurrenten auf Videokursen aufgebaut..."

    - Lennart Sparbier

    100% kostenlos registrieren · keine Kreditkarte notwendig

    👋 Wir warten bereits auf dich!

    Lerne das, was du wirklich brauchst.

    Im Gegensatz zu der Abendschule oder der alteingesessenen Uni lernst du bei codegree die Sprachen & Pakete, die wirklich im Jobmarkt gesucht werden.

    Logo von Python
    Logo von PyTorch
    Logo von Pandas
    Logo von Matplotlib
    Logo von Java
    Logo von NumPy
    Mehr erfahren

    100% kostenlos registrieren · keine Zahlungsdaten notwendig