Collectors.flatMapping is a utility method in the java.util.stream.Collectors class (introduced in Java 9) that combines the concepts of flattening a collection of collections and mapping elements into a single flattened stream of results.
Definition
Collectors.flatMapping allows you to apply a mapping function to elements of a stream and simultaneously flatten the resulting streams (or collections) into a single collection.
The syntax looks like this:
static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper,
Collector<? super U, A, R> downstream)
Parameters:
mapper: A function applied to each element of the stream to produce a sub-stream (or child elements).downstream: A collector used to collect the flattened elements produced by themapper.
Key Use-Cases:
- Flattening hierarchical data like lists of lists.
- Transforming and collecting elements into a single, flattened collection.
Behavior
- Applies a mapping function to transform each element of the data set into a
Stream(or subcollection). - Flattens these streams into a single continuous stream.
- Uses the provided downstream collector to collect the flattened results.
Example Explanation
Suppose you have a Map of students and their enrolled subjects:
Map<String, List<String>> studentSubjects = Map.of(
"Alice", List.of("Math", "Physics"),
"Bob", List.of("Biology", "Chemistry"),
"Charlie", List.of("Math", "History")
);
If you want to collect all the subjects in a flattened set (with no duplicates):
Set<String> allSubjects = studentSubjects.values().stream()
.collect(Collectors.flatMapping(List::stream, Collectors.toSet()));
System.out.println(allSubjects);
// Output: [Biology, Physics, History, Math, Chemistry]
Detailed Breakdown:
- Input: A
Stream<List<String>>(fromstudentSubjects.values()). - flatMapping:
- It applies
List::stream(mapping eachList<String>into aStream<String>). - Then flattens these child streams into a single stream of subjects.
- It applies
- toSet: Collects the flattened stream into a
Set(no duplicates allowed).
Comparing flatMapping to map
maptransforms each element into a sub-stream or collection but does not flatten.flatMappingcombines both mapping and flattening into one step, which simplifies working with nested structures.
Example differences:
List<List<String>> lists = List.of(
List.of("a", "b", "c"),
List.of("d", "e"),
List.of("f", "g", "h")
);
// Using flatMapping
Set<String> flatCollection = lists.stream()
.collect(Collectors.flatMapping(List::stream, Collectors.toSet()));
// Output: [a, b, c, d, e, f, g, h]
// Using map (no flattening)
List<Stream<String>> mappedStreams = lists.stream()
.map(List::stream)
.collect(Collectors.toList());
Custom Use Case and Comparisons
In your context (flatMap in CustomMonad), consider how Collectors.flatMapping can achieve similar goals in a Java Stream pipeline.
Example with nested collections:
class CustomMonadExample {
public static void main(String[] args) {
List<Optional<Integer>> optionalNumbers = List.of(
Optional.of(1),
Optional.of(2),
Optional.empty(),
Optional.of(4)
);
// Stream + flatMapping
List<Integer> flatMappedNumbers = optionalNumbers.stream()
.collect(Collectors.flatMapping(opt -> opt.stream(), Collectors.toList()));
System.out.println(flatMappedNumbers); // Output: [1, 2, 4]
}
}
Here:
- Each
Optionalis mapped to its stream usingopt.stream(). - Then these streams are combined (flattened) into a list using
flatMapping.
Keynotes:
- Use
Collectors.flatMappingwhen your processing involves nested structures or sub-streams, and you need to combine everything into a single collection. - It complements functionality such as
flatMapforstreamsbut applies for collecting results directly.
