I am trying to convert a Consumer
to a Runnable
. The following code does not generate any compiler errors in Eclipse IDE.
Consumer<Object> consumer;
Runnable runnable;
Object value;
...
runnable = () -> consumer.accept(value);
The following code generates a compiler error in Eclipse IDE.
ArrayList<Consumer<Object>> list;
Object value;
...
list.
stream().
map(consumer -> () -> consumer.accept(value));
The errors are:
Type mismatch: Can not convert from Stream<Object> to <unknown>.
The target type of this expression must be a functional interface.
How do I help the compiler convert a Consumer
to a Runnable
?
The following code fixes the problem but is very verbose.
map(consumer -> (Runnable) (() -> consumer.accept(value)));
Is there a more concise way to do this? I know I could create a static method which accepts a Consumer
and returns a Runnable
, but I don't think of that as more concise.
The error message is normal if you consider the expression:
list.stream().map(consumer -> () -> consumer.accept(value))
^--------------------------^
what is the type of that?
The problem is that the compiler has no way of determining the target type of the expression () -> consumer.accept(value)
. It certainly can be Runnable
, but it could also be MyAwesomeInterface
declared with:
@FunctionalInterface
interface MyAwesomeInterface { void foo(); }
In fact, it can comply to any functional interface that declares a functional method taking no parameter and returning no value. As such, this results in a compilation error.
There is no error when you explicitly store the lambda expression in a Runnable
with:
Runnable runnable = () -> consumer.accept(value);
because, then the compiler knows that the target type of that lambda is Runnable
.
The problem is more obscure when you consider:
List<Runnable> runnables = list.stream()
.map(consumer -> () -> consumer.accept(value))
.collect(Collectors.toList());
One could argue that the compiler may be able to infer the target type of that expression to be Runnable
since we're collecting that into a list of Runnable
. But, it doesn't and you have to help the compiler out a little and explicitly tell the compiler that the Stream
elements are Runnable
:
List<Runnable> runnables = list.stream()
.<Runnable> map(consumer -> () -> consumer.accept(value))
.collect(Collectors.toList());
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