Java 8 如何推断 lambdas 参数类型

2023-11-29

我目前正在使用 Java 中的 Vert.x,并注意到文档中的示例广泛使用 lambda 作为回调参数。例如:

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!");
  }
});

查看文档listen函数显示如下:

NetServer listen(int port,
                 String host,
                 Handler<AsyncResult<NetServer>> listenHandler)

我的问题是 JVM 如何有机会推导出通用数据类型,例如Handler<AsyncResult<NetServer>>从此类非信息对象中,例如res?对于像 JavaScript 这样执行鸭子类型的语言来说,这似乎很好,但对于像 Java 这样执行强类型的语言来说,这对我来说就不那么明显了。如果我们使用匿名类而不是 lambda,则所有数据类型都将出现。

- 编辑 - 正如@Zircon 已经解释的那样,Vert.x 文档中更好的示例可能是以下声明:

<T> void executeBlocking(Handler<Future<T>> blockingCodeHandler,
                         Handler<AsyncResult<T>> resultHandler)

文档中的用法示例:

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());
});

如果 type of 不可用,则只有 on 可用的方法Future and AsyncResults可以使用。


编译器以与您完全相同的方式推断类型。

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。泛型不会改变这一点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 8 如何推断 lambdas 参数类型 的相关文章

随机推荐

  • 成员名称不能与其在 g.cs 文件中的封闭类型相同

    我已经在 StackOverflow 中搜索过此问题的解决方案 但显然这次有所不同 在我的 Windows Phone 应用程序中 当用户按下特定按钮时 应用程序应将他重定向到特定的全景页面 因此我按照以下步骤操作 http blogs m
  • 如何使用java中的for循环从类创建新对象?

    我有一个名为 Card 的类 并且有这个 for 循环 int i for i 0 i lt 13 i Card cardNameHere new Card 我想做的是基于 for 循环创建新实例 例如 我希望名称为 card1 card2
  • Apache Kafka 中 Producer.properties 和 Consumer.properties 文件的使用

    Kafka 包内有一个 config 文件夹 其中包含各种配置文件 该文件夹包含 Consumer properties 和 Producer properties 文件 这些配置是在我们运行 Kafka 集群以及我们的代码连接到 kafk
  • MySQL:嵌套集很慢?

    我有一个看起来像这样的表 category 类别 id name 类别 seo 友好 url left id right id 当我运行这样的查询时 大约需要1秒 SELECT node category id AS node catego
  • Gnuplot:二维矢量图的可变颜色(和线宽)

    我正在尝试创建一个 2D 矢量图variablegnuplot 版本 4 4 中的颜色 和线宽 我查看了示例以获取要点 splot vectors dat u 1 2 3 4 rgb 5 6 7 w points pt 7 pointsiz
  • 如何从 json url 获取值

    我正在使用 AngularJS 我想动态获取价格的值 我的意思是从 url json 数据中获取它 这可能吗 这是url json url 这是我的控制器 angular module myApp zingchart angularjs c
  • 删除临时表后可以重新创建它吗?

    Given 存储过程中的代码 select bleh into tblTemp from FunctionThatReturnsTable some params do some stuff drop table tblTemp Error
  • SonarRunner with gradle:无法从服务器下载库

    我已经更新了Sonar到 4 5 1 LTS 版本 现在在我的 gradle 任务中出现以下错误并且无法修复它 Fail to download libraries from server 带有声纳运行器的 build gradle son
  • 如何将所有未版本控制的文件“svn 添加”到 SVN?

    我正在寻找一种好方法来自动将工作副本中的所有未版本化文件 svn 添加 到我的 SVN 存储库 我有一个实时服务器 可以创建一些应受源代码控制的文件 我想要一个简短的脚本 我可以运行它来自动添加这些内容 而不是一次逐一添加它们 我的服务器正
  • 在 Firefox 中获取停用的滚动条

    我有一个 Javascript 选项卡式对话框 其页面具有不同的高度 其中一些比浏览器窗口高 在 Internet Explorer 中 右侧始终有一个滚动条 当不需要时 它会显示为灰色 页面尺寸保持不变 没有问题 在 Firefox 中
  • Node.js + mysql 连接池

    我正在尝试找出如何构建我的应用程序以最有效地使用 MySQL 我正在使用 node mysql 模块 这里的其他线程建议使用连接池 所以我设置了一个小模块 mysql js var mysql require mysql var pool
  • 遥测采样而不影响错误/故障

    我想在应用程序洞察中记录成功调用的百分比 我看到了这个帖子https learn microsoft com en us azure azure monitor app sampling我认为固定速率采样在这里是合适的 但这是否同样影响所有
  • 用于将 AT 命令发送到调制解调器的 ADB shell 脚本 - 无法将控制权返回到 shell 并捕获输出

    我已经发布了类似的问题 但仍然无法完成我的工作 所以这是第二次尝试 其中 我想更清楚地说明我的绊脚石 所以基本上我在Android手机的adb shell中 通过发送AT命令与GPRS调制解调器通信 我可以通过将 at 命令重定向到代表调制
  • 在sql server上使用jdbcPreparedStatement获取查询计划

    使用 Statment resultSet getObject 将查询计划返回为 xml Connection conn getConnection String query SET SHOWPLAN XML on Statement st
  • OS X Lion 上的 32 位 OpenCV?可能的?

    我已经在谷歌上搜索并尝试了好几天 试图找出如何让 32 位 OpenCV 在 OS X Lion 上工作 但只能找到 64 位版本 所以我有以下问题 OpenCV 库有 32 位或 64 位架构 对吗 如何让 32 位 OpenCV 在 L
  • 使用 Scala“fromURL”的结果会抛出异常

    我正在尝试使用 Scala 的 scala io Source 对象获取一些网页 获取迭代器工作正常 但我无法在没有异常的情况下用它做任何事情 scala gt scala io Source fromURL http google com
  • SQL 根据引用多个其他变量的语句在新变量中返回 1,0

    我正在尝试创建一个新变量 根据一系列日期和阶梯级别 null E 在 MySQL 中填充 1 真 0 假 参见小提琴 http sqlfiddle com 9 9975e1 其中 record dates 和ladder levels 不一
  • 如何清除函数内的 setInterval?

    通常 我会将间隔设置为一个变量 然后像这样清除它var the int setInterval clearInterval the int 但为了让我的代码正常工作 我将其放入匿名函数中 function intervalTrigger s
  • twitter bootstrap 块级表单

    我正在尝试获取全宽登录表单 基本上 用户名 密码和按钮的输入字段都应该具有相同的长度 现在我可以使用跨度轻松获得此效果 问题是当我在用户名和密码 前面 添加一个图标时 输入字段超出了跨度 如果我将输入块级别应用于输入 并且按钮跨度仅到外部跨
  • Java 8 如何推断 lambdas 参数类型

    我目前正在使用 Java 中的 Vert x 并注意到文档中的示例广泛使用 lambda 作为回调参数 例如 NetServer server vertx createNetServer server listen 1234 localho