最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

Java 10 将带来升级版的 Lambda

  • 2017-01-22
  • 本文字数:2462 字

    阅读完需:约 8 分钟

一个新的JEP 将用于增强lambda 功能,提出的更改包括更好的消岐、对未使用的参数用下划线标注和外部变量的跟踪。虽然这些更改会使Java 中的lambda 表达式更类似于其它语言,但是初步讨论表明大家都不同程度地支持这个方案。这个JEP 补充了一系列其他建议来改进Java 语言,包括局部变量类型推断增强的枚举,所有这些改进都可能出现在Java 10 中。

尽管上述三个更改都与lambda 功能有关,但它们之间是相互独立的,其中一些可能会被舍弃,而其他的则取决于反馈情况。因此,我们将在本文中单独解释它们。

更好的消歧

当在Java 8 中添加lambda 功能时,必须修改类型推断以支持它们。然而,过去进行的更改并没有达到预期的效果,部分原因是担心这些更改会使第一次接触lambda 的开发者感到困惑。但是,从这一点来说,情况似乎正在改变,并且如果上下文提供了充足的信息,而编译器无法推断lambda 的类型时,一些开发者会感到沮丧。以下例子说明了lambda 类型推断如何工作:

复制代码
// Case 1: 推断为 Predicate <String> 的 lambda 类型
// 第一个重载方法将被调用
private void m(Predicate<String> ps) { /* ... */ }
private void m(Function<String, String> fss) { /* ... */ }
private void callingM() {
m((String s) -> s.isEmpty());
}
// Case 2: 没有足够的信息来独立地推断 lambda 的类型
// 不过 m2 没有被重载
// 将方法参数的签名应用于 lambda 来推断
// s 是 String 类型并且 s.length() 返回 Integer 类型
private void m2(Function<String, Integer> fsi) { /* ... */ }
private void callingM2() {
m2(s -> s.length());
}
// Case 3: 没有足够的信息来独立地推断 lambda 的类型
// m3 是重载的,但不同的版本有不同的参数数量
// 只有第一个版本和 parameters (1) 的数量匹配
// 将方法参数的签名应用于 lambda 来推断
// s 是 String 类型并且 s.length() 返回 Integer 类型
private void m3(Function<String, Integer> fsi) { /* ... */ }
private void m3(Function<String, Integer> fsi, String s) { /* ... */ }
private void callingM3() {
m3(s -> s.length());
}
// Case 4: 没有足够的信息来独立地推断 lambda 的类型。
// m4 的多个重载版本具有相同数量的可用参数
// Ambiguous call, ERROR
private void m4(Predicate<String> ps) { /* ... */ }
private void m4(Function<String, String> fss) { /* ... */ }
private void callingM4() {
m4(s -> s.isEmpty());
}

然而,对于最后一种情况来说,有足够的信息来判断 m4 的第一个重版本就是被调用的那个,尽管编译器当下并没有使用该信息。根据新建议,编译器可以按照以下步骤来解决歧义:

  1. 这两种可能性都假定 lambda 的参数是一个 _String_,所以 _s_ 可以被认为是 _String_ 类型
  2. 现在我们知道 _s_ 是一个 _String_,我们知道方法 _String.isEmpty()返回 _boolean
  3. 由于 lambda 返回 _boolean_,_m4_ 的第二个变体不匹配,因此它被舍弃
  4. 只剩下一个选项就是 _m4_ 的第一个变体,它与 lambda 的推断类型匹配,因此使用第一个变体

类似的论证也可以应用于方法引用。

用下划线表示未使用的参数

某些情况下,我们希望得到具有多个参数的 lambda 表达式,尽管不会使用所有的参数,但这要求开发者使用指示性名称来表示未使用的参数。这个更改将允许使用下划线来表示未使用的参数。

复制代码
Function<String, Integer> noneByDefault = notUsed -> 0; // 目前
Function<String, Integer> noneByDefault = _ -> 0; // 建议

这是一个其他几种语言都有的功能,如 Scala、Ruby 或 Prolog,但是,在 Java 中这不能轻易地实现,因为直到 Java 7,下划线仍然是一个有效的标识符,它可以在代码其它地方使用。为了引入这种更改而不需要重写大量的代码,这一功能需要逐步完善:

  1. Java 8:当下划线用作标识符时,会发出警告,阻止开发人员使用它 ; 下划线不允许作为 lambda 中的标识符(这不会导致任何向后不兼容问题,因为在 Java 8 之前的版本并没有 lambda 功能)。
  2. Java 9:Java 8 中的警告变为错误,确保将使用下划线作为标识符从 Java 代码语料库中删除。
  3. Java 10(或更高版本):下划线作为标识符重新引入,但仅适用于 lambda 表达式中未使用的参数。

通过初步的讨论来看,对这一更改的意见似乎并不一致 ; 一些用户喜欢新建议的简洁性,但另一些用户喜欢使用明确的名称。在进一步的讨论中可能达成共识。

参数的隐藏

这也许是新提出的功能中最有争议的一个。当前 lambda 参数不允许影响外部变量,意味着参数名称必须不同于当前作用域中可访问的任何变量 ; 这与其他包含作用域保持一致,比如 _while_ 循环或 _if_ 语句:

复制代码
String s = "hello";
if(finished) {
String s = "bye"; // 错误,s 已经定义
}
Predicate<String> ps = s -> s.isEmpty(); // 错误,s 已经定义

如果建议的更改继续下去,lambda 参数将能够重复使用和隐藏现有标识符。在某些情况下,这可能有利于用户,也就是说他们不需要使用其他不太直接的名称作为他们的 lambda 参数名称(上面的例子通常会被重写为 _s2 - > s2.isEmpty()_),但是,就像国际知名演讲者 Roy Van Rijn提出的那样,它也可能引入微小的错误:

复制代码
Map<String, Integer> map = /* ... */
String key = "theInitialKey";
map.computeIfAbsent(key, _ -> {
String key = "theShadowKey"; // shadow variable
return key.length();
});

目前,上述代码是不被允许的,但根据新提案这也可能是对的。如果标记为“shadow variable”的行被删除,代码将仍然可以编译和运行,但它会做完全不同的事情。

为了评估上述更改是否将被引入 Java 以及将以什么形式引入,他们还将进行更多的讨论。然而,毫无疑问的是,在 Java 8 中引入 lambda 只是未来 Java 语言的众多改进的第一步。

查看英文原文: Java 10 Could Bring Upgraded Lambdas


感谢薛命灯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-01-22 18:007266

评论

发布
暂无评论
发现更多内容

菜单展示的递归与非递归形式实现 (go语言版)

松小鼠

数据结构和算法

Your small business questions, answered

小韩

编程常见必备知识

梦醒了

编程 链表 函数

产品训练营第五周作业

朱航

智能云网:从时代所需,到运营商所向

脑极体

树莓派语音控制的一次小尝试

水战龟

树莓派

量化机器人APP开发|量化机器人软件系统开发

系统开发

云算力系统开发|云算力APP软件开发

系统开发

关于零售业数字化势在必行的一些杰出观点

小刘在学习

新零售

作业5

瑾瑾呀

2021 iOS底层提升计划

iOS底层

c语言函数与指针基础

赫鲁小夫

小结Spring中bean的作用域与生命周期

李楠

spring 生命周期 bean 作用域

流程图

王一凡

Linux Jenkins 自动打包vue部署到远程window服务器

三爻

Vue jenkins Win

计算机内部的总线是什么

FishyFine

计算机结构

OAtuth2.0 知多少

圣杰

oauth2.0 dotnet

助力文化荟萃,区块链或可打造“新”春晚?

CECBC

区块链 春晚

第二次书摘的微信视频号直播复盘

小匚

用户体验

【转】阿秀:C++经典49问49答

杨明越

Python编程入门手记

吕湛全

2021华为软件精英挑战赛正式开启,冠军奖金20万!

2021华为软件精英挑战赛

华为 软件 比赛 软件挑战赛

最值得期待的Python进阶宝典《Effective Python》第2版中文版来咯!

华章IT

Python 代码整洁 Python编程 EffectivePython Python进阶

Java 训练营第一周习题:02 加载字节码文件

现实中游走

Java

内娱完蛋了?不如让5G“出道”来抢救一下

脑极体

量化炒币机器人软件系统开发|量化炒币机器人app开发

系统开发

区块链技术带来金融服务的信任变革

CECBC

金融

作业5

赝品

「极客时间」课程购买用例

西西里奇

【编程小白福利】办公自动化--从VBA到Python

IT蜗壳-Tango

七日更 28天写作 2月春节不断更 办公自动化 IT蜗壳

区块链技术的价值传递

CECBC

区块链

Java 10将带来升级版的Lambda_Java_Abraham Marín Pérez_InfoQ精选文章