Unfortunately, it's impossible to achieve what you're asking in a concise way, since Java doesn't support extension or postfix functions. So, there is no way to add new method (e.g. .debugPrint()) into Map (the result of .collect).
( If you'd asked this question for Kotlin, the answer would've been to use .also{}. )
However, there are couple of tricks that come close.
1. The easy way
Just wrap the whole chain in the function that prints and returns the result.
- Pros: easy to write
- Cons: breaks the nice formatting of the chain
var result = printed(
landmarks
.stream()
.collect(Collectors.partitioningBy(b -> b.contains(" ")))
)
.entrySet()
.stream()
.flatMap(t -> t.getValue().stream())
.collect(Collectors.groupingBy(s -> !s.startsWith("S")));
// ...
// required helper function
static <T> T printed(T any) {
System.out.println(any);
return any;
}
2. The verbose way
You can create a function that wraps the Collector and prints it's result after it's finished collecting.
- Pros: stream chain still looks nice
- Cons: collector wrapper implementation is pretty verbose
var result = landmarks
.stream()
.collect(printed(Collectors.partitioningBy(b -> b.contains(" "))))
.entrySet()
.stream()
.flatMap(t -> t.getValue().stream())
.collect(Collectors.groupingBy(s -> !s.startsWith("S")));
// ...
// The required helper function
static <T, A, R> Collector<T, A, R> printed(Collector<T, A, R> wrapped) {
return new Collector<T, A, R>() {
@Override
public Supplier<A> supplier() {
return wrapped.supplier();
}
@Override
public BiConsumer<A, T> accumulator() {
return wrapped.accumulator();
}
@Override
public BinaryOperator<A> combiner() {
return wrapped.combiner();
}
@Override
public Function<A, R> finisher() {
return (A x) -> {
R res = wrapped.finisher().apply(x);
System.out.println(res);
return res;
};
}
@Override
public Set<Characteristics> characteristics() {
// Need to ensure IDENTITY_FINISH is removed, otherwise `finisher` is not called
return wrapped.characteristics().stream().filter(c -> c != IDENTITY_FINISH).collect(Collectors.toSet());
}
};
}
Both approaches print (in java 15):
{false=[Stonehenge], true=[Mount Fuji, Eiffel Tower, Statue of Liberty]}