编译器以与您完全相同的方式推断类型。
Netserver.listen
需要一个Handler<AsyncResult<NetServer>>
作为它的第三个参数。
Handler
是一个具有一种方法的顶点功能接口handle(E event)
。在这种情况下,E
is AsyncResult<NetServer>
.
在这里插入 lambda 使其取代Handler.handle
。因此,单一论证res
必须是类型AsyncResult<NetServer>
。这就是为什么它可以调用AsyncResult.succeeded
没有问题。
Simply:
第三个论证是不可能的listen
绝不是Handler<AsyncResult<NetServer>>
,所以 lambda 必须提供一个类型的参数<AsyncResult<NetServer>>
.
Edit:
关于在 lambda 中使用嵌套泛型,请考虑此类:
public class myClass<T> {
public void doSomething(int port, String host, Handler<AsyncResult<T>> handler) {
//Stuff happens
}
}
(在这种情况下,我们不关心发生的事情。)
然而,考虑一下我们需要如何call这个方法。我们需要有一个 MyClass 的实例,这也意味着我们需要在调用之前声明泛型类型doSomething
:
MyClass<String> myObj = new MyClass<String>();
result = myObj.doSomething(port, host, res -> {
if (res.succeeded()) {
System.out.println("I did a thing!");
} else {
System.out.println("I did not do a thing!");
}
});
在这种情况下,编译器可以still infer res
as an AsyncResult<String>
, 因为T
is String
在这种情况下。如果我打开包装AsyncResult
,然后我可以打电话String
方法如toUpperCase
等等。
如果您最终引用了MyClass<?>
并尝试类似地使用 lambda,res
将被推断为AsyncResult<?>
。 (您可以打开?
类型,但因为它的类型在编译时无法得知,所以您被迫将其视为Object
.)
如果我们在声明期间没有声明泛型类型,我们将收到有关它的警告,并且由于原始类型的原因,此代码将无法工作(感谢 Holger):
MyClass myObj = new MyClass(); //Generic type warning
result = myObj.doSomething(port, host, res -> {
if (res.succeeded()) { //Error
System.out.println("I did a thing!");
} else {
System.out.println("I did not do a thing!");
}
});
因为我们已经声明了myObj
作为原始类型MyClass
, res
成为类型Object
(Not AsyncResult<Object>
),所以我们不能调用succeeded
on it.
这样,您就不可能在不确切知道通过其参数推断出什么类型的情况下使用 lambda。
可能有一些高级方法可以使用 lambda 代替泛型类型在其自己的签名中声明的方法,但我需要做一些研究来说明这些观点。本质上,即使可能发生这种情况,您也需要致电MyClass.<MyType>doSomethingStatic
为了在声明 lambda 之前声明类型,以便可以推断类型。
Simply:
您不能在无法推断类型的情况下使用 lambda。泛型不会改变这一点。