Tom*_*mas 2 java lambda java-8 vert.x
我目前正在使用Java中的Vert.x,并注意到文档中的示例广泛使用lambdas作为回调参数.例如:
NetServer server = vertx.createNetServer();
server.listen(1234, "localhost", res -> {
if (res.succeeded()) {
System.out.println("Server is now listening!");
} else {
System.out.println("Failed to bind!");
}
});
Run Code Online (Sandbox Code Playgroud)
查看listen函数文档显示以下内容:
NetServer listen(int port,
String host,
Handler<AsyncResult<NetServer>> listenHandler)
Run Code Online (Sandbox Code Playgroud)
我的问题是JVM如何有机会推断出通用数据类型Handler<AsyncResult<NetServer>>,例如诸如res?之类的非信息性对象?这对于像鸭子这样的类型的JavaScript这样的语言来说似乎很好,但是对于像Java那样强类型的语言来说,这对我来说并不那么明显.如果我们使用匿名类而不是lambda,那么所有数据类型都将在盘子上.
--EDIT--正如@Zircon已经解释的那样,Vert.x文档中可能更好的例子是遵循声明:
<T> void executeBlocking(Handler<Future<T>> blockingCodeHandler,
Handler<AsyncResult<T>> resultHandler)
Run Code Online (Sandbox Code Playgroud)
以及来自docs的用法示例:
vertx.executeBlocking(future -> {
// Call some blocking API that takes a significant amount of time to return
String result = someAPI.blockingMethod("hello");
future.complete(result);
}, res -> {
System.out.println("The result is: " + res.result());
});
Run Code Online (Sandbox Code Playgroud)
如果没有类型,则只能使用Future和AsyncResults可以使用的方法.
编译器以与您完全相同的方式推断类型.
Netserver.listen将a Handler<AsyncResult<NetServer>>作为其第三个参数.
Handler是一个带有一个方法的vertx FunctionalInterface handle(E event).在这种情况下,E是AsyncResult<NetServer>.
在这里插入一个lambda使它取而代之Handler.handle.因此,单个参数res必须是类型AsyncResult<NetServer>.这就是为什么它可以AsyncResult.succeeded毫无问题地打电话.
只是:
第三个参数不可能listen是任何东西Handler<AsyncResult<NetServer>>,所以lambda必须提供一个类型的参数<AsyncResult<NetServer>>.
编辑:
关于在lambda中使用嵌套泛型,请考虑以下类:
public class myClass<T> {
public void doSomething(int port, String host, Handler<AsyncResult<T>> handler) {
//Stuff happens
}
}
Run Code Online (Sandbox Code Playgroud)
(在这种情况下,我们不关心发生的事情.)
但是,请考虑我们如何调用此方法.我们需要有一个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!");
}
});
Run Code Online (Sandbox Code Playgroud)
在这种情况下,编译器可以仍然推断res为AsyncResult<String>,因为T是String在这种情况下.如果我解开了AsyncResult,我可以调用String类似于toUpperCase诸如此类的方法.
如果您最终引用a 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!");
}
});
Run Code Online (Sandbox Code Playgroud)
因为我们已经声明myObj为原始类型MyClass,res变为类型Object(Not AsyncResult<Object>),所以我们不能调用succeeded它.
这样,你就不可能在不知道你用它的参数推断出什么类型的情况下使用lambda.
可能有一些使用lambda代替方法的高级方法,其泛型类型在其自己的签名中声明,但我需要做一些研究来说明这些要点.基本上,即使可能发生这种情况,您也需要调用MyClass.<MyType>doSomethingStatic以在声明lambda之前声明类型,以便可以推断出类型.
只是:
您不能使用无法推断类型的lambda.泛型不会改变这一点.
| 归档时间: |
|
| 查看次数: |
655 次 |
| 最近记录: |