【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

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:007254

评论

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

从 0 到 1 教你在亚马逊云科技中部署动态网站 Typecho 系统

亚马逊云科技 (Amazon Web Services)

php 亚马逊 typecho

Flink Watermark 机制及总结

腾讯云大数据

大数据 flink 实战 流计算 Oceanus

云效代码管理 Codeup 是什么?别说你还不知道

阿里云云效

阿里云 DevOps 云原生 云效 Codeup

云原生时代的运维体系进化

阿里巴巴中间件

云计算 阿里云 云原生 中间件

怎么做需求管理,手把手教你做需求管理

阿里云云效

云计算 阿里云 项目管理 需求管理 研发敏捷

求菩萨保佑?IT人员的系统稳定性公式

凌晞

架构 质量管理 技术管理

带你详细了解mongodb数据库

编程江湖

团队需要移动CRM系统的原因

低代码小观

移动 CRM 客户关系管理 CRM系统 客户关系管理系统

专访 KubeVela 核心团队:如何简化云原生复杂环境下的应用交付和管理

阿里巴巴中间件

阿里云 云原生 OAM KubeVela

面试高并发,凉了!!(全程高能,建议收藏)

冰河

并发编程 多线程 高并发 协程 异步编程

SQLite简介

网易云信

sqlite

网络安全kali之利用宏感染word文档获取shell

侠盗安全

网络安全 kali kali Linux

华米科技 x StarRocks:让智能穿戴数据焕发新活力

StarRocks

数据库 数据分析 StarRocks

瞄准程序员招聘痛点,ShowMeBug让面试代码操作可“回放”

ShowMeBug

CODING 公开课火热报名中!

CODING DevOps

项目管理 公开课 瀑布模型

每周问答精选:PolarDB 和 PolarDB-X 的区别是什么?

阿里云数据库开源

数据库 阿里云 开源 polarDB

RadonDB MySQL on Kubernetes 2.1.3 发布!

RadonDB

MySQL 数据库 Kubernetes 高可用 RadonDB

SpringBoot性能怎样优化

编程江湖

物联网——智能点灯搭建

kof11321

一文读懂蓝绿发布、A/B 测试和金丝雀发布的优缺点

阿里巴巴中间件

阿里云 云原生 中间件 蓝绿发布 A/B 测试

Apache ShardingSphere Agent 可观察性实用指南

SphereEx

数据库 ShardingSphere SphereEx apache 社区

知识社会的到来:知识管理与知识协同

小炮

知识管理

百万大数据错题笔记

Clarke

【高效开发】不止面对面,Cloud Studio 推出 MetaWork 云协作套件

CODING DevOps

疫情 协同办公 Cloud Studio 云端编码

业内高规格!数字峰会七大板块之一,行业盛会诚邀采购商莅临!

科技热闻

功能解读|快速上手 OceanBase 数据迁移服务

OceanBase 数据库

oceanbase OMS

MapReduce的Shuffle过程及Hadoop优化(包括:压缩、小文件、集群优化)

编程江湖

企业电子文档管理系统哪个好

小炮

文档 企业管理软件

不想业务被中断?快来解锁华为云RDS for MySQL新特性

华为云数据库小助手

GaussDB 华为云数据库 rds for mysql

【Altium Designer】工程的组成 & 创建

謓泽

3月月更

什么是敏感信息检测,敏感信息检测,安全视图 | 云效

阿里云云效

云计算 阿里云 云原生 敏感信息检测 代码检测

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