JAVA Tutorial #68

Defaultmethoden und Collections-Erweiterungen

2024-05-24 | credits: paisorn@stock.adobe

Overview

Im Rahmen der in Java 8 neu hinzugekommenen Mechanismen der Lambda-Programmierung, wurde auch das Sprachfeature der Defaultmethoden eingeführt. Insbesondere die Collection-Schnittstellen profitieren durch den Einbau von Defaultmethoden und es lassen sich Listen so erst mit Lambda-Funktionen steuern. In diesem Tutorial zeigen wir dir einige dieser Defaultmethoden und wie du sie zur Vereinfachung in der Arbeit mit Listen einsetzt. 

Was sind Defaultmethoden?

Bei der Integration von Lambdas in das bestehende JDK war schnell klar, dass für eine sinnvolle Nutzung bestehende Klassen und Interfaces mit entsprechender Lambda-Kompatibilität erweitert werden mussten. Jedoch gab es dabei ein Problem: Es war bislang nicht möglich, Interfaces nachträglich zu ändern, ohne dass es vernichtende Kompatibilitätsprobleme auf Programme gehabt hätte, die auf die geänderten Interfaces zurückgriffen. Das Problem lag in der Natur von Interfaces: Wenn eine Methode dem Interface hinzugefügt wurde, musste diese von allen Klassen, die das Interface implementieren, auch realisiert werden. 

Mit Java 8 wurde dieses Dilemma durch das Konzept der Defaultmethoden für Interfaces behoben. 

  • Defaultmethoden sind spezielle Methoden mit einer konkreten Implementierung in Interfaces.

Vor Java 8 bestand ein Interface per Definition vollständig aus abstrakten Methoden (= Methoden ohne Implementierung).

Durch den Einsatz von Defaultmethoden kann ein Interface nun also auch Methoden mit Methodenkörper und Implementierung haben. Eine Bedingung gibt es allerdings:

  • Der Compiler besteht auf das Schlüsselwort default bei der Deklaration der Defaultmethoden in Interfaces. 

Schauen wir uns nun drei verschiedene Interfaces mit ihren neuen Defaultmethoden an. Die Interfaces stammen in unserem Beispielen alle aus dem Collection-Framework und vereinfachen uns durch die hinzugewonnene Lambda-Unterstützung die Arbeit mit Listen deutlich.

forEach

Durch eine Liste zu iterieren ist in der Programmierung alltäglich. Als Alternative zur klassischen Lösung mit einer Schleifenkonstruktion lässt sich diese Aufgabe nun auch mit einem Lambda-Ausdruck erledigen.

Dazu wurde in Java 8 das Interface Iterable (das von allen gängigen Listenklassen implementiert wird) um die Default-Methode forEach() erweitert. forEach() erwartet als Parameter einen Lambda-Ausdruck, der das funktionale Interface Consumer implementiert:

List<String> liste = Arrays.asList("The", "last", "of", "us");

Consumer<String> ausgabe = p -> System.out.println(p);
liste.forEach(ausgabe);

Anstatt dem Zwischenschritt, nämlich die Lambda-Funktion mit einer Variablen ausgabe zu referenzieren und diese dann der forEach()-Methode zu übergeben, lässt sich das Ganze auch nochmnals abkürzen und in nur einer einzigen Zeile lösen: 

liste.forEach(p -> System.out.println(p));

removeIf

Java 8 hat dem Collection-Interface die Default-Methode namens removeIf hinzugefügt. Damit können wir um ein vielfaches einfacher spezifizieren, welches Element unter welcher Bedingung aus einer Liste entfernt werden soll. Als Parameter erwartet die Methode einen Lambda-Ausdruck, der das funktionale Interface Predicate implementiert:

List<String> liste = new ArrayList<>();
liste.add("Vader");
liste.add("Snoke");
System.out.println(liste); // [Vader, Snoke]
Predicate<String> predicate = p -> p.startsWith("S");
liste.removeIf(predicate);
System.out.println(liste); // [Vader]

In der fünften Zeile erstellen wir ein Predicate-Referenz mit entsprechender Lambda-Implementierung, die alle Objekte der Liste, die mit einem "S" beginen markiert. In der nächsten Zeile übergeben wir dann predicate der Methode removeIf, damit die entsprechenden Listen-Objekte zu entfernen (hier: "Snoke"). 

Klar, geht das auch in nur einer Zeile: 

liste.removeIf(p -> p.startsWith("S"));

replaceAll

Eine weitere praktische Default-Methode ist replaceAll, die das Interface List erweitert hat. Der Methode lässt sich ein Lamba-Ausdruck als Parameter des funktionalen Interfaces UnaryOperator übergeben: 

List<Integer> liste = Arrays.asList(1, 2, 3);
UnaryOperator<Integer> u = p -> p * 2;
liste.replaceAll(u);
System.out.println(liste); // [2, 4, 6]

Und hier die Lösung in nur einer Code-Zeile: 

liste.replaceAll(p -> p * 2);
Werbung

Java lernen

Werde zum Java Profi!

PHP Lernen

Lerne serverbasierte Programmierung

JavaScript lernen

Skille dein Webcoding

FALCONBYTE.NET

Handmade with 🖤️

© 2018-2023 Stefan E. Heller

Impressum | Datenschutz | Changelog

Falconbyte Youtube Falconbyte GitHub facebook programmieren lernen twitter programmieren lernen discord programmieren lernen