在 Stream.map() 中将 Consumer 转换为 Runnable

Convert Consumer into Runnable inside Stream.map()

我正在尝试将 Consumer 转换为 Runnable。以下代码 不会 在 Eclipse IDE.

中生成任何编译器错误
Consumer<Object> consumer;
Runnable runnable;
Object value;

...
runnable = () -> consumer.accept(value);

以下代码在 Eclipse 中生成编译器错误 IDE。

ArrayList<Consumer<Object>> list;
Object value;

...

list.
   stream().
   map(consumer -> () -> consumer.accept(value));

错误是:

Type mismatch: Can not convert from Stream<Object> to <unknown>.
The target type of this expression must be a functional interface.

如何帮助编译器将 Consumer 转换为 Runnable

下面的代码解决了这个问题,但是非常冗长。

map(consumer -> (Runnable) (() -> consumer.accept(value)));

有更简洁的方法吗?我知道我可以创建一个接受 Consumer 和 returns 和 Runnable 的静态方法,但我不认为那样更简洁。

如果考虑表达式,错误消息是正常的:

list.stream().map(consumer -> () -> consumer.accept(value))
                              ^--------------------------^
                                what is the type of that?

问题是编译器无法确定表达式的目标类型() -> consumer.accept(value)。它当然可以是 Runnable,但也可以是 MyAwesomeInterface 声明方式:

@FunctionalInterface
interface MyAwesomeInterface { void foo(); }

事实上,它可以符合任何声明不带参数且不返回值的函数式方法的函数式接口。因此,这会导致编译错误。

将 lambda 表达式显式存储在 Runnable 中时没有错误:

Runnable runnable = () -> consumer.accept(value);

因为,那么编译器就知道那个 lambda 的目标类型是 Runnable.


当你考虑的时候问题就比较模糊了:

List<Runnable> runnables = list.stream()
                               .map(consumer -> () -> consumer.accept(value))
                               .collect(Collectors.toList());

有人可能会争辩说,编译器可能能够推断出该表达式的目标类型是 Runnable,因为我们正在将其收集到 Runnable 的列表中。但是,it doesn't 并且您必须稍微帮助编译器并明确告诉编译器 Stream 元素是 Runnable:

List<Runnable> runnables = list.stream()
                               .<Runnable> map(consumer -> () -> consumer.accept(value))
                               .collect(Collectors.toList());