You can create a custom Collector
(here called StreamInterceptor
), even though this does not really fit the purpose of a collector.
What will the custom collector do?
- Convert the
Stream<T>
to a List<T>
- Call the Consumer<List>, which will in your case print the length of the list.
- Return a new
Stream<T>
of the List<T>
Main method
Here I've just broken down your problem into the filtering of a simple string list and printing them to the console at the end.
public static void main(String[] args) {
List<String> myList = List.of("first", "second", "third");
myList.stream()
.filter(string -> !string.equals("second"))
.collect(printCount())
.forEach(System.out::println);
}
/**
* Creates a StreamInterceptor, which will print the length of the stream
*/
private static <T> StreamInterceptor<T> printCount() {
Consumer<List<T>> listSizePrinter = list -> System.out.println("Stream has " + list.size() + " elements");
return new StreamInterceptor<>(listSizePrinter);
}
When initializing the StreamInterceptor
you can define a Consumer, that takes in the intermediate list constructed from the stream and performs some action on it. In your case it will just print the size of the list.
New StreamInterceptor
class
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Stream;
class StreamInterceptor<T> implements Collector<T, List<T>, Stream<T>> {
private final Consumer<List<T>> listConsumer;
public StreamInterceptor(Consumer<List<T>> listConsumer) {
this.listConsumer = listConsumer;
}
@Override
public Supplier<List<T>> supplier() {
return ArrayList::new;
}
@Override
public BiConsumer<List<T>, T> accumulator() {
return List::add;
}
@Override
public BinaryOperator<List<T>> combiner() {
return (list1, list2) -> {
list1.addAll(list2);
return list1;
};
}
@Override
public Function<List<T>, Stream<T>> finisher() {
return list -> {
listConsumer.accept(list);
return list.stream();
};
}
@Override
public Set<Characteristics> characteristics() {
return Collections.emptySet();
}
}
Resources