有没有办法捕获某种类型的所有功能接口?

ski*_*iwi 1 java lambda java-8

假设我有以下手工制作的功能界面:

@FunctionalInterface
public static interface OnHandCardAddedListener extends HandView {
    @Override
    void onCardAdded(final Card card);

    @Override
    default void onCardPlayed(final int cardIndex) { }

    @Override
    default void onCardsSwapped(final int cardIndexOne, final int cardIndexTwo) { }
}
Run Code Online (Sandbox Code Playgroud)

它是签名Card -> void,因此该功能接口的实现是lambda,它是Consumer<Card>功能接口的实现.

我知道我可能应该在界面中使用默认方法扩展Consumer<Card>和实现它.applyOnHandCardAddedListener

但为什么不只是开箱即用?

使用以下测试:

private void acceptConsumer(final Consumer<Card> cardConsumer) {

}
Run Code Online (Sandbox Code Playgroud)

和测试代码:

Consumer<Card> cardConsumer = card -> { };
acceptConsumer(cardConsumer);
OnHandCardAddedListener viewCardConsumer = card -> { };
acceptConsumer(viewCardConsumer); // does not compile
Run Code Online (Sandbox Code Playgroud)

这里acceptConsumer(viewCardConsumer)不编译,但为什么不编译?据我所知,他们应该解决相同类型的lambda,因此两者都可以用于具体的定义.

编辑,我忘了提到为什么这很重要,考虑我需要使用java.util.function 没有提供的功能接口的情况,然后我们可以看到两个客户需要实现自己的具体功能做同样的接口. 因此需要一种方法来概括其用法.

Kep*_*pil 5

这不起作用的原因是您已经为lambda表达式分配了一个类型.

考虑这个例子:

acceptConsumer(card -> {});
Run Code Online (Sandbox Code Playgroud)

在这里,编译器可以检查参数的类型应该是什么.由于提供的lambda是该参数类型的合法表示,所以一切都很好.
将此与您的示例进行比较:

OnHandCardAddedListener viewCardConsumer = card -> { };
acceptConsumer(viewCardConsumer); // does not compile
Run Code Online (Sandbox Code Playgroud)

在这里,您没有将lambda传递给方法,而是一种与预期完全不同的类型.使用lambda表达式进行初始化的事实viewCardConsumer完全无关紧要.此代码等同于以下代码,我认为您不希望编译:

OnHandCardAddedListener viewCardConsumer = new OnHandCardAddedListener() {
    @Override
    void onCardAdded(final Card card){  };
};
acceptConsumer(viewCardConsumer); // does not compile either
Run Code Online (Sandbox Code Playgroud)