Funktionale Interfaces
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 39 von 87.
Ein funktionales Interface ist ein Interface, das genau eine abstrakte Methode enthält. Diese Einschränkung auf eine einzige Methode macht funktionale Interfaces besonders, da sie mithilfe von Lambda-Ausdrücken implementiert werden können, was einen prägnanteren Programmierstil ermöglicht.
Java bietet die @FunctionalInterface-Annotation an, um ein Interface explizit als funktional zu kennzeichnen. Obwohl sie optional ist, hilft diese Annotation dem Compiler, Fehler zu erkennen, falls Sie versehentlich eine zweite abstrakte Methode hinzufügen:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Sie können ein funktionales Interface auf herkömmliche Weise mit einer Klasse oder prägnanter mit einem Lambda-Ausdruck implementieren:
// Herkömmliche Implementierung
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Lambda-Ausdruck (viel kürzer!)
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Funktionale Schnittstellen können weiterhin Standardmethoden und statische Methoden haben, da diese nicht zur Regel der einzelnen abstrakten Methode zählen. Javas Paket java.util.function bietet viele integrierte funktionale Schnittstellen wie Predicate, Function und Consumer, denen Sie bei der Arbeit mit Streams und Collections häufig begegnen werden.
Aufgabe
EinfachLassen Sie uns ein System zur String-Transformation unter Verwendung von funktionalen Interfaces und Lambda-Ausdrücken erstellen. Sie werden einen flexiblen Textprozessor entwickeln, der verschiedene Transformationen auf Strings anwenden kann – alles basierend auf einem einzigen funktionalen Interface.
Sie werden Ihren Code in drei Dateien organisieren:
StringTransformer.java: Definieren Sie ein funktionales Interface, das eine beliebige String-Transformationsoperation darstellt. Markieren Sie es mit der@FunctionalInterface-Annotation, um sicherzustellen, dass es funktional bleibt. Ihr Interface sollte eine einzige abstrakte Methode namenstransformdeklarieren, die einen String entgegennimmt und einen String zurückgibt.TextProcessor.java: Erstellen Sie eine Klasse, die Ihr funktionales Interface zur Textverarbeitung nutzt. Sie sollte ein Feld für einenStringTransformerund einen Konstruktor zu dessen Initialisierung besitzen. Fügen Sie eine Methode namensprocess(String text)hinzu, die den Transformer auf den übergebenen Text anwendet und das Ergebnis zurückgibt. Dieses Design ermöglicht es Ihnen, jedes beliebige Transformationsverhalten über den Konstruktor zu injizieren.Main.java: Führen Sie alles zusammen, indem Sie verschiedene Transformationen mittels Lambda-Ausdrücken erstellen. Sie erhalten zwei Eingaben: einen Text-String und einen Operationstyp (upper,loweroderreverse).Erstellen Sie basierend auf dem Operationstyp einen
TextProcessormit dem entsprechenden Lambda:upper: wandelt Text in Großbuchstaben umlower: wandelt Text in Kleinbuchstaben umreverse: kehrt den Text um (Hinweis: verwenden SieStringBuilder)
Rufen Sie dann
process()mit dem Eingabetext auf und geben Sie das Ergebnis in diesem Format aus:Result: [transformed text]
Sie erhalten zwei Eingaben: den zu transformierenden Text (String) und den Operationstyp (String).
Beachten Sie, wie dieselbe TextProcessor-Klasse völlig unterschiedliche Operationen ausführen kann, je nachdem, welches Lambda Sie übergeben – das ist die Stärke von funktionalen Interfaces!
Spickzettel
Ein funktionales Interface ist ein Interface mit genau einer abstrakten Methode. Es kann mithilfe von Lambda-Ausdrücken für prägnanten Code implementiert werden.
Verwenden Sie die @FunctionalInterface-Annotation, um ein Interface als funktional zu kennzeichnen (optional, aber empfohlen):
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Funktionale Interfaces können traditionell oder mit Lambda-Ausdrücken implementiert werden:
// Traditionelle Implementierung
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Lambda-Ausdruck
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Funktionale Interfaces können Default- und statische Methoden haben, ohne die Regel der einzelnen abstrakten Methode zu verletzen.
Javas java.util.function-Paket bietet integrierte funktionale Interfaces wie Predicate, Function und Consumer.
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String operation = scanner.nextLine();
TextProcessor processor;
// TODO: Erstellen Sie basierend auf dem Operationstyp einen TextProcessor mit dem entsprechenden Lambda:
// - "upper": wandelt Text in Großbuchstaben um
// - "lower": wandelt Text in Kleinbuchstaben um
// - "reverse": kehrt den Text um (Hinweis: StringBuilder verwenden)
// TODO: Rufen Sie process() mit dem Eingabetext auf und geben Sie das Ergebnis aus
// Ausgabeformat: "Result: [transformed text]"
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem