Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Diese Lerneinheit wurde für typische Bachelor-Klausuren konzipiert. So prüfen wir · Fehler entdeckt? Melde ihn uns oder markiere die fragliche Stelle direkt im Text oben.
Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Stell dir vor du willst eine Liste sortieren — aber nicht alphabetisch, sondern nach Notenschnitt, oder nur die ungeraden Zahlen behalten, oder jede Zahl verdoppeln. Du müsstest jedes Mal eine neue Funktion schreiben. Lambdas sind Mini-Funktionen, die du wie Werte weitergeben kannst — und so beliebige Logik in fertige Methoden einbauen.
Seit Java 8 Teil der Sprache. Klausur-Vorkommen in 5/13 WInf-Prog-1-Klausuren (P3, Vertiefung — in Prog-2 mehr).
Klausur-Tipp: Bei "Was gibt der folgende Stream zurück?" — geh Operation für Operation durch. filter wirft raus, map verändert, reduce kombiniert. Notiere dir nach jeder Operation die Zwischen-Liste.
Anmelden, um den Fortschritt zu speichern.
Nächster Schritt
Aktives Abrufen festigt Wissen schneller als nochmal lesen.
Stell dir vor du willst eine Liste sortieren — aber nicht alphabetisch, sondern nach Notenschnitt, oder nur die ungeraden Zahlen behalten, oder jede Zahl verdoppeln. Du müsstest jedes Mal eine neue Funktion schreiben. Lambdas sind Mini-Funktionen, die du wie Werte weitergeben kannst — und so beliebige Logik in fertige Methoden einbauen.
Seit Java 8 Teil der Sprache. Klausur-Vorkommen in 5/13 WInf-Prog-1-Klausuren (P3, Vertiefung — in Prog-2 mehr).
Lambda: Eine anonyme Funktion, die du wie einen Wert behandeln kannst — speichern, weitergeben, später ausführen. Higher-Order-Funktion: Eine Funktion, die andere Funktionen als Parameter nimmt oder zurückgibt.
Die klassische Lösung war eine anonyme Klasse:
List<String> namen = Arrays.asList("Charlie", "Alice", "Bob");
Collections.sort(namen, new Comparator<String>() {
public int compare(String a, String b) {
return a.length() - b.length();
}
});
5 Zeilen für "sortiere nach Länge". Mit Lambda:
Collections.sort(namen, (a, b) -> a.length() - b.length());
Ein Drittel der Schreibarbeit, gleicher Effekt. Das ist der Killer-Vorteil von Lambdas.
// Klassisch (3 Varianten):
(int a, int b) -> { return a + b; } // mit Typ-Annotation + Block
(a, b) -> { return a + b; } // Typen inferiert
(a, b) -> a + b // Single-Expression, return implizit
Faustregeln:
x -> x * 2(a, b) -> a + b(a, b) -> { int s = a + b; return s; }Ein Lambda implementiert immer ein funktionales Interface — ein Interface mit genau einer abstrakten Methode. Die häufigsten aus java.util.function:
| Interface | Signatur | Was es macht |
|---|---|---|
Function<T, R> | R apply(T t) | Wert → Wert (Transformation) |
Predicate<T> | boolean test(T t) | Wert → bool (Filter) |
Consumer<T> | void accept(T t) | Wert → nichts (Action) |
Supplier<T> | T get() | nichts → Wert (Erzeuger) |
BiFunction<T,U,R> | R apply(T t, U u) |
Beispiele:
Function<Integer, Integer> verdoppeln = x -> x * 2;
verdoppeln.apply(5); // 10
Predicate<Integer> isGerade = n -> n % 2 == 0;
isGerade.test(4); // true
Consumer<String> drucker = s -> System.out.println(s);
drucker.accept("Hallo"); // gibt Hallo aus
map, filter, forEachListen / Streams haben Methoden, die andere Funktionen als Argument nehmen. Höhere Ordnung = sie verarbeiten Funktionen.
List<Integer> zahlen = List.of(1, 2, 3, 4, 5);
// filter: behalte nur die geraden
zahlen.stream()
.filter(n -> n % 2 == 0) // [2, 4]
.forEach(System.out::println);
// map: verdoppele jede Zahl
List<Integer> verdoppelt = zahlen.stream()
.map(n -> n * 2) // [2, 4, 6, 8, 10]
.collect(Collectors.toList());
// reduce: alle aufsummieren
int summe = zahlen.stream()
.reduce(0, (acc, n) -> acc + n); // 15
Daumenregel:
Manchmal ist das Lambda nur ein Aufruf einer existierenden Methode. Dann gibt's eine Kurzschreibweise mit :::
// Lambda
list.forEach(s -> System.out.println(s));
// Method-Reference (identisch)
list.forEach(System.out::println);
// String::length statt s -> s.length()
list.stream().map(String::length);
Lesbarer in vielen Fällen, aber nicht überall sinnvoll — bei nicht-trivialen Lambdas lieber explizit.
Funktionen lassen sich verketten:
Function<Integer, Integer> verdoppeln = x -> x * 2;
Function<Integer, Integer> plusZehn = x -> x + 10;
Function<Integer, Integer> kombi = verdoppeln.andThen(plusZehn);
kombi.apply(3); // (3 * 2) + 10 = 16
Function<Integer, Integer> kombi2 = verdoppeln.compose(plusZehn);
kombi2.apply(3); // (3 + 10) * 2 = 26
andThen: erst die eine, dann die andere. compose: umgekehrt (innere zuerst).
1. Lambda implementiert ein funktionales Interface. Genau EINE abstrakte Methode. java.util.function hat die wichtigsten 40+.
2. Lambda-Syntax kennen. Single-Param: keine Klammern (x -> x*2). Single-Expression: kein return, kein Block ((a,b) -> a+b).
3. Higher-Order-Methoden machen mehr mit weniger Code. map/filter/reduce sind funktionale Standard-Operationen.
4. Method-Reference :: ist Syntax-Sugar für ein Lambda das eine bestehende Methode aufruft. System.out::println statt s -> System.out.println(s).
5. Lambdas sind nicht Threads. Ein Lambda läuft NICHT automatisch parallel — es ist nur eine Funktion. Für Parallelität: stream().parallel() oder ExecutorService.
1. return vergessen bei mehrzeiligem Body. (a, b) -> { a + b } ist Compile-Fehler — entweder (a, b) -> a + b oder (a, b) -> { return a + b; }.
2. Effectively-final-Regel. Lambda kann nur lokale Variablen lesen, die effectively final sind (nicht verändert nach der Zuweisung). Innerhalb des Lambdas reassign → Compile-Error.
int x = 10;
Function<Integer, Integer> f = n -> n + x; // ok
x = 20; // ← x ist nicht mehr effectively final → Compile-Error oben
3. Stream nicht 2x nutzen. Ein Stream ist EINMAL nutzbar. stream.filter(...).count() und dann nochmal stream.forEach(...) → IllegalStateException.
4. null in Streams. null kann durch filter/map laufen und Probleme später machen. Vorher .filter(Objects::nonNull) als Schutz.
5. Lambda mit Seiteneffekt in map/filter. map und filter sollten pur sein (kein State ändern, nur returnen). Wenn du Seiteneffekte willst → forEach am Ende.
Eine Liste [1, 2, 3, 4, 5, 6] läuft durch verschiedene Stream-Operationen. Du kannst die einzelnen Schritte ein-/ausschalten und siehst, wie sich das Endresultat verändert.
So entwickelst du Intuition für filter, map, reduce und ihre Zusammenarbeit.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Tipp: Bei "Was gibt der folgende Stream zurück?" — geh Operation für Operation durch. filter wirft raus, map verändert, reduce kombiniert. Notiere dir nach jeder Operation die Zwischen-Liste.
6 Aufgaben zu Lambda-Syntax, funktionalen Interfaces, Stream-Operationen.
Klausurfragen mit Lösungen (6)
Antwort: x -> x * 2
Erklärung: Java-Syntax ist `x -> x * 2`. JavaScript wäre `=>`, Python `lambda x:`, klassisches Java `function(x)`. Pfeil-Operator `->` ist Java-Spezifika.
Antwort: Ein Interface mit genau einer abstrakten Methode
Erklärung: Funktionales Interface = genau EINE abstrakte Methode (default-Methoden zählen nicht). Beispiele: Function, Predicate, Consumer, Comparator. Nur funktionale Interfaces können von Lambdas implementiert werden.
Antwort: Falsch
Erklärung: FALSCH. Lambdas sind reine Funktionen, kein Threading. Für Parallelität: `stream().parallel()` oder ExecutorService. Lambdas sind nur eine kompakte Schreibweise — Ausführung ist sequenziell wie normaler Code.
Typ: Wahr/Falsch
Antwort: filter
Erklärung: filter behält nur die Elemente, für die der Predicate true ist. map TRANSFORMIERT jedes (kein Element verschwindet), reduce KOMBINIERT zu einem Wert, forEach iteriert.
Richtige Antworten: Lambdas können effectively-final lokale Variablen lesen; `x -> x * 2` ist valides Java; Method-References wie `String::length` sind eine Kurzschreibweise; Ein funktionales Interface hat 1 abstrakte Methode
Erklärung: Richtig: effectively-final Zugriff erlaubt, Lambda-Syntax mit ->, Method-References, 1 abstrakte Methode. Falsch: Lambdas können lokale Variablen NICHT reassign (Compile-Error); Streams sind EINMAL nutzbar (IllegalStateException sonst).
Typ: Multi-Select
Zuordnungen:
Erklärung: Die 4 Basis-Interfaces aus java.util.function. Function (transformiert), Predicate (testet), Consumer (verbraucht), Supplier (erzeugt).
Typ: Zuordnung
Klausurfragen mit Lösungen (6)
Antwort: 60
Erklärung: Schritt 1 filter: [2,4]. Schritt 2 map *10: [20, 40]. Schritt 3 reduce mit sum: 20+40=60. Klausur-Klassiker: jeden Schritt einzeln durchgehen.
Antwort: (a, b) -> a + b
Erklärung: Bei MEHREREN Parametern sind Klammern PFLICHT: `(a, b) -> a + b`. Bei einem Parameter sind Klammern optional: `x -> x*2` oder `(x) -> x*2`. `=>` ist JavaScript, nicht Java.
Antwort: Wahr
Erklärung: RICHTIG. Beides ist ein Consumer<String> mit gleicher Wirkung. `::` ist Method-Reference-Syntax, syntaktischer Zucker für das entsprechende Lambda.
Typ: Wahr/Falsch
Antwort: Compile-Fehler: x ist nicht effectively final
Erklärung: Compile-Fehler! Lambdas dürfen lokale Variablen nur LESEN, wenn sie effectively final sind. `x = x + n` ist eine Reassignment → Bricht das. Lösung: int[]{5} (Array bleibt final, Inhalt wandelt) oder besser: reduce verwenden.
Lösungen pro Lücke:
Erklärung: Standard-Vokabular Lambdas + Streams. Funktionales Interface, Predicate (filter), Function (map), reduce (Aggregation). Klausur-Vokabular.
Typ: Lückentext
Richtige Reihenfolge:
Erklärung: Erst Quelle, dann filter (gerade), dann map (quadrieren), dann sammeln. Reihenfolge wichtig: filter VOR map ist effizienter (weniger Elemente zu transformieren). Endresultat: [4, 16, 36, 64, 100].
Typ: Reihenfolge
| 2 Werte → Wert |