I'm having a Java 8 stream of numbers:
Stream<Number> numbers = ...;
I'd like to iterate the stream and invoke a specific consumer based on the type of each element. I.e. for Integer
elements I'd like to invoke a Consumer<Integer>
, for Long
a Consumer<Long>
etc.
There is the forEach()
method but this expects a Consumer<? super Number>
, requiring that implementation (usually a Lambda expression) to instanceof-switch on the exact type itself.
In terms of an API, I'm essentially looking for something like this:
numbers.forEach( callbacks -> {
callbacks.on( Integer.class, i -> { /* handle Integer */ } );
callbacks.on( Long.class, l -> { /* handle Long */ } )
} );
Is there any existing API which would allow me to register a specific consumer per stream element sub-type in a way similar to this?
The forEach method accepts a Consumer as a parameter. The consumer can be simplified with a lambda expression or a method reference. In the example, we go over the elements of a list with forEach . The consumer simply prints each of the elements.
Stream forEach() method in Java with examplesStream forEach(Consumer action) performs an action for each element of the stream. Stream forEach(Consumer action) is a terminal operation i.e, it may traverse the stream to produce a result or a side-effect.
java. util. function. Consumer<T> Consumer function type Parameters: T - object type to be passed to the Consumer accept method Consumer function methods: void accept(T t) This method operates on a single object passed in as an argument.
Are you sure you don't want to just run the stream twice? It will be more readable.
But if you want, you can define a type-checking consumer like this:
public static<T> Consumer<Object> acceptType(Class<T> clazz, Consumer<? super T> cons) {
return t -> {
if (clazz.isInstance(t)) {
cons.accept(clazz.cast(t));
}
};
}
You can then combine multiple consumers using andThen
:
Consumer<Object> combined = acceptType(Integer.class, i -> ...)
.andThen(acceptType(Long.class, lng -> ...))
If you want to hide andThen
, you can define
static<T> Consumer<T> doAll(Consumer<T>... consumers) {
return Arrays.stream(consumers)
.reduce(Consumer::andThen)
.orElse(t -> {});
}
Then it becomes
nums.forEach(doAll(
acceptType(Integer.class, i -> ...),
acceptType(Long.class, lng -> ..),
...
));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With