I have a method that receives a collector. The collector should combine incoming lists:
reducing(Lists.newArrayList(), (container, list) -> {
container.addAll(list);
return container;
})
This seems like a very common scenario to me, and I believe Java's own collector should have something to cover this use case, but I cannot remember what. Besides, I want it to return ImmutableList
.
To obtain a "flattened" list of elements from a nested collection firstly you need to apply flatMapping()
which takes a function that turns an element to a stream and a collector as second argument. And to get an immutable list apply toUnmodifiableList()
as a downstream collector inside the flatMapping()
(as already mentioned by racraman and hfontanez in their comments, since they pointed that earlier the credits for this answer should belong to them).
List<List<Integer>> nestedList = List.of(
List.of(1, 2),
List.of(3, 4)
);
nestedList.stream()
.collect(Collectors.flatMapping(List::stream,
Collectors.toUnmodifiableList()))
.forEach(System.out::println);
output
1
2
3
4
A more common use-case for Collector.flatMapping()
is when each element of the stream holds a reference to a collection, rather than being a collection itself.
Consider the following scenario.
We have a collection of Order
s. Each Order
has an id and a collection of Item
s. And we want to obtain a map from this collection of orders so that based on the order id we can get a list of items.
In this situation Collector.flatMapping()
is indispensable because by applying the flatMap()
in the middle of the stream we will lose access to the orderId
in the collect()
. Hence, flattening should happen inside the collect()
operation.
A method that implements the logic described above might look this:
public Map<String, List<Item>> getItemsByOrderId(Collection<Order> orders) {
return orders.stream()
// some logic here
.collect(Collectors.groupingBy(Order::getId,
Collectors.flatMapping(order ->
order.getItems().stream().filter(somePredicate),
Collectors.toList())));
}