这两个是等价的。第一个,您正在定义 lambda 表达式的参数 - 请注意,您的括号涵盖了整个更改参数。这允许编译器知道要匹配哪个重载。
第二个只是一个演员表。您正在告诉编译器要匹配此 lambda 的哪种方法签名。 (MapChangeListener<String, String>) 将整个 lambda 表达式转换为 MapChangeListener,因此编译器知道它确实是 addListener(MapChangeListener)。由于您已经定义了MapChangeListener 定义的单个参数,因此编译器也不会抱怨它是错误的。
编辑
现在我有更多的时间,我会给你一些具体的例子,这将帮助你更深入地理解。
public class Foo {
public final void bar(IntfA a) {}
public final void bar(IntfB b) {}
public final void bar(IntfC c) {}
}
@FunctionalInterface
public interface IntfA {
void doSomething(Double a);
}
@FunctionalInterface
public interface IntfB {
void doSomething(Integer a);
}
@FunctionalInterface
public interface IntfC {
void doSomething(Double a);
}
public class Test {
public static void main(String[] args)
{
Foo foo = new Foo();
foo.bar(a -> {}); // Ambiguous
foo.bar((Integer a) -> {}); // Okay, this is IntfB
foo.bar((Double a) -> {}); // Ambiguous between IntfA and IntfC
foo.bar((IntfC) a -> {}); // No longer ambiguous since you specified that it's IntfC
foo.bar((IntfC) (a, b) -> {}); // Method signature does not match IntfC
}
}
编辑 2
您似乎需要更多帮助。
当您定义方法bar(IntfA) 时,您期望的是IntfA 的对象,无论IntfA 是接口类型还是类类型。
然后,lambda 表达式只是编译时方便的语法。当我写foo.bar((Integer a) -> {})时,编译器最终会把它变成Java字节码(在.class文件中),相当于这个:
foo.bar(new IntfB() {
public void doSomething(Integer a) {
}
});
我们称之为Anonymous Class。
使用 lambda 的最大和可能唯一的区别是,它使您的代码更短。有时它使您的代码更具可读性,有时它使您的代码可读性降低。
由于 lambda 减少了您需要输入的内容的数量,因此当存在示例中的重载方法时,很容易使 lambda 表达式对编译器产生歧义。请记住,编译器需要首先确定哪个重载,然后它会帮助您为您实例化对象。
当您编写 foo.bar((Double a) -> {}) 时,编译器会注意到您有一个 lambda 表达式,该表达式接受一个 Double 参数并且不返回任何内容。然后它将查看bar() 的三个重载。它注意到bar(IntfA) 和bar(IntfC) 都接受一个函数接口,并且两个接口的方法都接受一个Double 参数并且什么都不返回。此时,编译器不确定是否应该生成相当于哪两组代码的字节码:
选择 1:
foo.bar(new IntfA() {
public void doSomething(Double a) {
}
});
选择 2:
foo.bar(new IntfC() {
public void doSomething(Double a) {
}
});
如果你写foo.bar((IntfC) a -> {}),你已经在暗示编译器你希望它匹配foo.bar(IntfC)重载。编译器看到你有一个未知类型的参数,但由于你已经告诉它匹配IntfC,它会假定参数是Double。
现在到最后一部分,调用foo.bar(IntfA) 不会自动调用IntfA 指定的doSomething(Double a) 方法。在我的示例中,bar() 方法什么也没做,但通常人们会写一些有用的东西。
再举例:
public final void bar(IntfB obj) {
if (obj == null)
System.out.println("I was waiting for an IntfB object but I got nothing!");
else
obj.doSomething(100);
}
foo.bar((Integer a) -> {
System.out.println("I got " + a + " marks for my exam!");
});
这会导致“我的考试得了 100 分!”打印在控制台上。