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.
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.
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:
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.
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));
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"));
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);
Java Basics
[Java einrichten] [Variablen] [Primitive Datentypen] [Operatoren] [if else] [switch-case] [Arrays] [Schleifen]
Objektorientierung
[Einstieg] [Variablen ] [Konstruktor] [Methoden] [Rekursion] [Statische Member] [Initializer] [Pass-by-value] [Objektsammlungen] [Objektinteraktion] [Objekte löschen]
Klassenbibliothek
[Allgemeines] [String ] [Math] [Wrapper] [Scanner] [java.util.Arrays] [Date-Time-API]
Vererbung
[Einstieg Vererbung] [Konstruktoren bei Vererbung ] [Der protected Zugriffsmodifikator] [Abstrakte Klassen und Methoden] [Polymorphie in Java] [Typumwandlung] [Die Klasse Object] [Die toString()-Methode] [Objekte vergleichen] [Was ist ein Interface?]