【发布时间】:2017-02-01 14:02:56
【问题描述】:
请考虑这个例子:
import java.util.function.Consumer;
public class Example {
public static void main(String[] args) {
Example example = new Example();
example.setConsumer(test -> System.out.println("passed string is " + test)); //uses MyConsumer, why ?
example.getConsumer().accept("Test 1");
example.setConsumer((MyConsumer<String>)test -> System.out.println("passed string is " + test)); //uses MyConsumer
example.getConsumer().accept("Test 2");
example.setConsumer((Consumer<String>)test -> System.out.println("passed string is " + test)); //uses Consumer
example.getConsumer().accept("Test 3");
}
private Consumer<String> consumer;
public Consumer<String> getConsumer() {
return consumer;
}
public void setConsumer(Consumer<String> consumer) {
this.consumer = consumer;
}
public void setConsumer(MyConsumer<String> consumer) {
this.consumer = consumer;
}
@FunctionalInterface
public interface MyConsumer<T> extends Consumer<T> {
@Override
default void accept(T value) {
System.out.println("In consumer string: " + value); //example thing to do
receive(value);
}
void receive(T value);
}
}
我感兴趣的是第一个测试。为什么使用 MyConsumer 而不是 Consumer ?如果我有更多不同的可能消费者具有相同的 lambda 结构,谁有优先权?另外,我在测试 2 中所做的演员表被我的 IDE 标记为Redundant。这意味着 lamdba 首先是作为 MyConsumer 创建的。为什么会这样?
我正在使用带有 Javac 的 IntelliJ Idea。
【问题讨论】:
-
不知道你用的是哪个IDE。我认为是 JVM 使用对象的运行时类型来“决定”。
-
我认为 Java 选择了最具体的类型,在这种情况下是
MyConsumer。如果MyConsumer不是Consumer的子接口,我想你会得到一个错误,说这是一个模棱两可的调用。 -
它选择最具体的方法。例如,如果您有
MyConsumer2<T> extends Consumer<T>和setConsumer(MyConsumer2<String> consumer),那么第一次调用将是模棱两可的,并且您会遇到编译时错误。另请参阅JLS 15.12.2.5。 -
这个问题本身导致了建议:不要使用不同的功能接口作为方法重载的标准。重载本身可能很难理解。从一开始就针对不同目标类型对 lambda 进行类型推断的重载是一个坏主意。在某些情况下,甚至编译器编写者也必须调试他们自己的编译器才能找出重载决议的正确答案。普通程序员在这里没有机会。
标签: java lambda java-8 functional-interface