
Funktionale Datenverarbeitung in Java hat sich mit Java 8 verändert. Vor Java 8 griffen Entwickler oft auf Guava für funktionale Operationen zurück. Mit der Einführung von Lambdas und Streams in Java 8 wechselten viele weg von Guava. Allerdings bot Guava unveränderliche Datenstruktur-Implementierungen, während die Java Collections API nicht für Unveränderlichkeit konzipiert wurde, was zu Laufzeit-Überraschungen führt.
Das Javaslang-Projekt geht einen anderen Weg, indem es die Java Collections API vollständig verlässt und eine eigene API
mit unveränderlichen Datenstrukturen erstellt. Obwohl es Iterable für die Interaktion mit Java Collections
implementiert, zielt es darauf ab, die Collections API komplett zu ersetzen.
Daten aus einer Liste in eine Map transformieren
1:1 Map
Javaslang:
List<Integer> source = List.of(1,2,3,4);
Map<String, Integer> result = source.groupBy(e -> e.toString())
.mapValues(v -> Iterables.getOnlyElement(v));
Java 8:
Collection<Integer> source = ImmutableList.of(1, 2, 3, 4);
Map<String, Integer> result = source.stream()
.collect(Collectors.toMap(e -> e.toString(), x -> x));
Javaslang gibt unveränderliche Implementierungen zurück, ohne bei Kollisionen Exceptions zu werfen – anders als Java 8.
Transformation von Schlüssel und Wert
Javaslang:
List<Person> source = List.of(Person.of("Klaus",42),Person.of("Bert",33));
Map<String, Integer> result = source.toMap(e -> Tuple.of(e.name, e.age));
Java 8:
Collection<Person> source = ImmutableList.of(Person.of("Klaus",42),Person.of("Bert",33));
Map<String, Integer> result = source.stream()
.collect(Collectors.toMap(e -> e.name, e -> e.age));
Werte anhand eines Schlüssels gruppieren
Javaslang:
List<String> source = List.of("Klaus","Klaas","Susi","Jane","Jan","Jochen");
Map<String, List<String>> result = source.groupBy(e -> e.substring(0,1));
Java 8:
Collection<String> source = ImmutableList.of("Klaus","Klaas","Susi","Jane","Jan","Jochen");
Map<String, ? extends Collection<String>> result = source.stream()
.collect(Collectors.groupingBy(e -> e.substring(0,1)));
Listen aus Listen
Listen filtern und transformieren
Javaslang:
List<Integer> src = List.of(1,2,3,4,5,6,7);
List<String> result = src
.filter(e -> e % 2 == 0)
.map(e -> e.toString());
Java 8:
List<Integer> src = Lists.newArrayList(1,2,3,4,5,6,7);
Collection<String> result = src.stream()
.filter(e -> e % 2 == 0)
.map(e -> e.toString())
.collect(Collectors.toList());
Der wesentliche Unterschied: Javaslang liefert Zwischenergebnisse als unveränderliche Objekte ohne terminale Operationen, während Streams eine finale Collection erfordern.
Flatmap - ein Universalwerkzeug
Das Konzept kombiniert die Elementtransformation in Listen mit anschließender Verkettung. Anwendungsfälle umfassen:
- Leere Ergebnislisten
- Einelementige Listen
- Mehrelementige Listen
Listen aneinander hängen
Javaslang:
List<List<String>> src = List.of(List.of("A","B","C"), List.of("D","E"), List.of("F","G","H","I","J"), List.of("Z"));
List<String> result = src.flatMap(e -> e);
Java 8:
List<ImmutableList<String>> src = ImmutableList.of(ImmutableList.of("A","B","C"),
ImmutableList.of("D","E"),
ImmutableList.of("F","G","H","I","J"),
ImmutableList.of("Z"));
List<String> result = src.stream()
.flatMap(e -> e.stream())
.collect(Collectors.toList());
Javaslang in Action
String result = List.of("Susi","Sara","Jane")
.zipWithIndex()
.toMap(t -> Tuple.of(t._2(), t._1()))
.map(t -> t._1+":"+t._2)
.foldLeft(null, (l,r) -> l==null ? r : l+" - "+r);
Dieses Beispiel demonstriert Verkettung: eine Liste in indizierte Tupel konvertieren, eine Map erstellen, diese transformieren und zu einem einzelnen String falten.
Zusammenfassung
Während Java Streams sequenzielle Datenverarbeitung effektiv bewältigen, fehlt ihnen die Unterstützung für andere Konstrukte. Javaslang bietet ein umfassendes Toolkit, das besonders wertvoll für seinen standardmäßigen Unveränderlichkeitsansatz ist.

