C4G: Map, Filter und Reduce einzeln anwenden

Ich kann map(), filter() und reduce() einzeln verwenden, um Listen zu transformieren, zu filtern und zu aggregieren.

Lernziele

# Lernziel Beantwortet in
1 Ich kann map() verwenden, um eine Transformation auf jedes Element einer Liste anzuwenden. 1. Map anwenden
2 Ich kann filter() verwenden, um Elemente aus einer Liste nach einem Kriterium auszuwählen. 2. Filter anwenden
3 Ich kann reduce() verwenden, um eine Liste auf einen einzelnen Wert zu reduzieren (z.B. Summe berechnen). 3. Reduce anwenden

Überblick

In Java werden map, filter und reduce über die Stream API verwendet. Ein Stream wird aus einer Collection erzeugt, verarbeitet die Elemente und sammelt das Ergebnis ein.

Operation Was sie tut Eingabe → Ausgabe
map() Transformiert jedes Element Stream → Stream (gleiche Anzahl)
filter() Wählt Elemente nach Kriterium Stream → Stream (gleiche oder weniger Elemente)
reduce() Fasst alle Elemente zusammen Stream → Einzelwert
import java.util.stream.*;

1. Map anwenden

map(funktion) wendet eine Funktion auf jedes Element an und gibt einen neuen Stream zurück.

// Alle Zahlen verdoppeln
var numbers = List.of(1, 2, 3, 4, 5);
var doubled = numbers.stream()
    .map(x -> x * 2)
    .toList();
System.out.println(doubled);  // [2, 4, 6, 8, 10]

map() verändert die Originalliste nicht, sondern erzeugt eine neue:

System.out.println(numbers);  // [1, 2, 3, 4, 5] — unverändert

Map-Beispiele

// Quadratzahlen berechnen
var squares = List.of(1, 2, 3, 4).stream()
    .map(x -> x * x)
    .toList();
System.out.println(squares);  // [1, 4, 9, 16]

// Preise mit Mehrwertsteuer (8.1%)
var prices = List.of(10.0, 25.0, 50.0);
var withTax = prices.stream()
    .map(p -> Math.round(p * 1.081 * 100.0) / 100.0)
    .toList();
System.out.println(withTax);  // [10.81, 27.03, 54.05]

// Strings in Grossbuchstaben
var words = List.of("hallo", "welt", "java");
var upper = words.stream()
    .map(String::toUpperCase)
    .toList();
System.out.println(upper);  // [HALLO, WELT, JAVA]

Map mit Methodenreferenz

static String formatName(String name) {
    var stripped = name.strip();
    return stripped.substring(0, 1).toUpperCase()
         + stripped.substring(1).toLowerCase();
}

var rawNames = List.of("  alice", "BOB  ", " charlie ");
var cleanNames = rawNames.stream()
    .map(Main::formatName)
    .toList();
System.out.println(cleanNames);  // [Alice, Bob, Charlie]

2. Filter anwenden

filter(predicate) behält nur die Elemente, für die das Predicate true zurückgibt.

// Nur gerade Zahlen behalten
var numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8);
var even = numbers.stream()
    .filter(x -> x % 2 == 0)
    .toList();
System.out.println(even);  // [2, 4, 6, 8]

Mehr Beispiele

// Nur positive Zahlen
var values = List.of(-5, 3, -1, 7, 0, -2, 4);
var positive = values.stream()
    .filter(x -> x > 0)
    .toList();
System.out.println(positive);  // [3, 7, 4]

// Nur Strings mit mindestens 5 Zeichen
var words = List.of("Hi", "Hallo", "Welt", "Stream", "OK");
var longWords = words.stream()
    .filter(w -> w.length() >= 5)
    .toList();
System.out.println(longWords);  // [Hallo, Stream]

// Nur bestandene Prüfungen (Note >= 4.0)
var grades = List.of(5.5, 3.5, 4.0, 2.0, 6.0, 4.5);
var passed = grades.stream()
    .filter(g -> g >= 4.0)
    .toList();
System.out.println(passed);  // [5.5, 4.0, 6.0, 4.5]

Filter mit Methodenreferenz

static boolean isValidEmail(String email) {
    int atIndex = email.indexOf('@');
    return atIndex > 0 && email.substring(atIndex).contains(".");
}

var emails = List.of("alice@example.com", "invalid", "bob@mail.ch", "no-at-sign");
var valid = emails.stream()
    .filter(Main::isValidEmail)
    .toList();
System.out.println(valid);  // [alice@example.com, bob@mail.ch]

3. Reduce anwenden

reduce(identity, accumulator) kombiniert alle Elemente schrittweise zu einem einzelnen Wert. Der Accumulator nimmt immer zwei Argumente: den bisherigen Wert und das nächste Element.

// Summe aller Zahlen
var numbers = List.of(1, 2, 3, 4, 5);
int total = numbers.stream()
    .reduce(0, (acc, x) -> acc + x);
System.out.println(total);  // 15

Wie Reduce funktioniert (Schritt für Schritt)

Für reduce(0, (acc, x) -> acc + x) mit [1, 2, 3, 4, 5]:

Schritt acc x Ergebnis
Start 0   0
1 0 1 1
2 1 2 3
3 3 3 6
4 6 4 10
5 10 5 15

Weitere Beispiele

// Produkt aller Zahlen
var numbers = List.of(2, 3, 4, 5);
int product = numbers.stream()
    .reduce(1, (acc, x) -> acc * x);
System.out.println(product);  // 120

// Maximum finden
var values = List.of(3, 7, 2, 9, 4);
int maximum = values.stream()
    .reduce(Integer.MIN_VALUE, (acc, x) -> x > acc ? x : acc);
System.out.println(maximum);  // 9

// Strings zusammenfügen
var words = List.of("Funktionale", "Programmierung", "ist", "elegant");
String sentence = words.stream()
    .reduce("", (acc, w) -> acc.isEmpty() ? w : acc + " " + w);
System.out.println(sentence);  // Funktionale Programmierung ist elegant

Reduce ohne Startwert

Ohne Startwert gibt reduce ein Optional zurück, da die Liste leer sein könnte:

var numbers = List.of(1, 2, 3);
Optional<Integer> sum = numbers.stream()
    .reduce((acc, x) -> acc + x);
System.out.println(sum.orElse(0));  // 6

// Leere Liste
Optional<Integer> empty = List.<Integer>of().stream()
    .reduce((acc, x) -> acc + x);
System.out.println(empty.orElse(0));  // 0

Spezialisierte Reduce-Methoden

Für primitive Typen bietet Java optimierte Varianten:

var numbers = List.of(1, 2, 3, 4, 5);

// mapToInt erzeugt einen IntStream mit spezialisierten Methoden
int sum = numbers.stream().mapToInt(Integer::intValue).sum();
OptionalInt max = numbers.stream().mapToInt(Integer::intValue).max();
double avg = numbers.stream().mapToInt(Integer::intValue).average().orElse(0);

System.out.println(sum);                // 15
System.out.println(max.orElse(0));      // 5
System.out.println(avg);                // 3.0

This site uses Just the Docs, a documentation theme for Jekyll.