【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

与 Brian Goetz 聊 Java 的模式匹配

  • 2017-10-08
  • 本文字数:3905 字

    阅读完需:约 13 分钟

InfoQ 采访了来自 Oracle 的 Java 语言架构师 Brian Goetz 和编程语言研究员 Gavin Bierman ,谈论了有可能被集成到 Java 语言中的模式匹配

动机

之所有要研究是否有可能在 Java 中加入模式匹配,主要还是为了改进 Java 的语言特性。假如有这样的一段代码:

复制代码
if (obj instanceof Integer) {
int intValue = ((Integer) obj).intValue();
// 使用 intValue
}

这段代码做了三个操作:

  • 判断 obj 是否是一个 Integer 类型
  • 将 obj 转成 Integer 类型
  • 从 Integer 中抽取出 int

现在再来看看在 if…else 结构的语句中判断其他类型。

复制代码
String formatted = "unknown";
if (obj instanceof Integer) {
int i = (Integer) obj;
formatted = String.format("int %d", i);
}
else if (obj instanceof Byte) {
byte b = (Byte) obj;
formatted = String.format("byte %d", b);
}
else if (obj instanceof Long) {
long l = (Long) obj;
formatted = String.format("long %d", l);
}
else if (obj instanceof Double) {
double d = (Double) obj;
formatted = String.format("double %f", d);
}
else if (obj instanceof String) {
String s = (String) obj;
formatted = String.format("String %s", s);
}
...

虽然上述的代码是可运行的,也很好理解,但写起来很枯燥(太多重复的样板代码),也容易产生 bug。过多的样板代码会让业务逻辑变得含糊不清——如果 instanceof 方法已经判断出传入的实例是何种类型,那么就没必要重复进行转型了。

Goetz 和 Bierman 解释了他们想要做出的改进。

我们认为是时候让 Java 拥抱模式匹配了,而不仅仅是把它作为一种临时的解决方案。很多编程语言从 60 年代开始就已经采用了模式匹配,包括面向文本的编程语言 SNOBOL4 AWK 、函数编程语言 Haskell 和 ML,以及最近的面向对象编程语言 Scala 和 C#。

模式由判断谓语(predicate)和一系列绑定变量(binding variable)组成,判断谓语被应用在目标上面,而绑定变量是从目标中抽取出来的。

复制代码
if (x matches Integer i) {
// 使用 i
}

Goetz 和 Bierman 使用过各种模式匹配,它们使用了关键字 matches 和 exprswitch。

matches 操作符

matches 操作符可以用来代替 instanceof 操作。例如:

复制代码
String formatted;switch (obj) {
case Integer i: formatted = String.format("int %d", i); break;
case Byte b: formatted = String.format("byte %d", b); break;
case Long l: formatted = String.format("long %d", l); break;
case Double d: formatted = String.format(“double %f", d); break;
default: formatted = String.format("String %s", s);
}...
{1}

只有当变量 x 与某个 Integer 实例匹配时,变量 i 才能被使用。如果把 Integer 类型扩展到其他类型,那么 if…else 结构里的类型转换就可以省掉了。

switch 的改进

Goetz 和 Bierman 解释说,“switch 语句就是一种最完美的模式匹配”。例如:

复制代码
String formatted;switch (obj) {
case Integer i: formatted = String.format("int %d", i); break;
case Byte b: formatted = String.format("byte %d", b); break;
case Long l: formatted = String.format("long %d", l); break;
case Double d: formatted = String.format(“double %f", d); break;
default: formatted = String.format("String %s", s);
}...
{1}

上面的代码清晰易懂。不过,Goetz 和 Bierman 也指出了 switch 的一个局限——“它只是一个语句,所以分支也必须是语句。我们希望可以把它们变成三元操作符那样的表达式,这样就可以保证只对其中的一个表达式求值”。

他们建议引入一种新的表达式语句——exprswtich。

复制代码
String formatted =
exprswitch (obj) {
case Integer i -> String.format("int %d", i);
case Byte b -> String.format("byte %d", b);
case Long l -> String.format("long %d", l);
case Double d -> String.format(“double %f", d);
default -> String.format("String %s", s);
};
...
{1}

Goetz 和 Bierman 建议的模式如下所述。

  • 类型检测模式(将被转型的目标绑定到变量)
  • 解构模式(解构目标并进行递归匹配)
  • 常量模式(等值匹配)
  • 变量模式(任意匹配并绑定目标)
  • 下划线模式(任意匹配)

以下是 Goetz 与 InfoQ 的谈话内容。

InfoQ:在你发布论文后,社区都有哪些反馈?

Goetz:我们收到了非常积极的反馈。在其他语言里使用过模式匹配的人都很喜欢这个特性,他们也希望能够在 Java 中使用它。对于那些之前没有使用模式匹配的人,我们希望他们能够学会使用这个特性,我们认为很有必要在 Java 里添加这一特性。

InfoQ:Scala 的匹配操作符对 Java 模式匹配的设计有多大的影响?有什么事情是 Scala 的匹配操作能做的而 Java 却做不到的吗?

Goetz:Scala 只是众多启发我们在 Java 中加入模式匹配的语言之一。为一门语言添加特性不外乎从其他语言那里“移植”,但实际上,我们并不希望做得跟 Scala 完全一样,我们只要能够做到 Scala 的一部分,同时也能做 Scala 做不到的。

我们认为我们更有可能将模式匹配深度集成到对象模型中,比 Scala 有过之而无不及。Scala 的模式是静态的,难以重载或覆盖。虽说能够做到这样已经很好了,但我们希望能够做得更好。

解构(deconstruction)是构造(construction)的另一面,面向对象编程语言让我们可以构造对象(构造器、工厂、构建器),而解构将给我们带来更丰富的 API。虽说模式匹配与面向函数语言有一定的历史渊源,但我们相信它在面向对象语言里将会得到更好的发扬。

人们对语言特性津津乐道,不过我们认为语言特性真正的作用应该是为软件库提供更好的服务,而模式匹配将帮助我们写出更简单、更安全的软件库。

以 java.lang.Class 的两个方法为例:

复制代码
public boolean isArray() { ... }
public Class getComponentType() { ... }

第二个方法需要以第一个方法返回 true 作为前提。对于 API 提供者(需要些更多代码,也需要更多的测试)和用户(容易出错)来说,涉及多 API 的逻辑操作就意味着复杂性。从逻辑上看,这两个方法就是一个模式,融合了“判断这个类是否是一个数组类”和“根据条件抽取组件类型”。如果能够通过以下的表达式来表达,那么代码写起来就更简单了,而且不容易出错。

if (aClass matches Class.arrayClass(var componentType)) { ... }

InfoQ:这次是否把让 Scala rebase 模式匹配作为目标(比如 Scala 2.12 就基于接口对 trait 进行了 rebase)?

Goetz:与 Lambda 表达式一样,我们希望在设计这一语言特性的过程中,能够找到一些构建块,并把它们集成到底层的平台中,让其他语言也能从中获益,并为多个语言提供更好的互操作性。

InfoQ:Scala 在实现这一特性时添加了很多额外的字节码用于支持解构 case 类型,这样会造成负面影响吗?

Goetz:这样做最大的问题在于,编译器不再只是个编译器了,它往类成员里添加了语义。虽然这样做很方便,但可能不是用户想要的,比如,比较数组要用 Arrays.equals(),而不能用 Object.equals()。

InfoQ:解构是否仅限于数据类(data class)?

Goetz:我们计划分几次来发布模式匹配功能,最开始先发布类型检测,然后是数据类的解构模式,最后是用户自定义的解构模式。虽说解构不会仅限于数据类,但这一过程还是需要一些时间。

InfoQ:你能够解释一下数据类和值类型(value type)之间的关系吗?

Goetz:它们之间是一种正交关系。值就是一种合体,没有标识。通过显式地拒用标识,运行时可以优化内存布局,扁平化对象头部,更自由地跨同步点缓存值组件。数据类简化了类表示和 API 协定之间复杂的关系,编译器就可以注入常用的类成员,如构造器、模式匹配器、equals 方法、hashCode 方法和 toString 方法。有些类可以被声明成值类(value class),有些则适合被声明成数据类,或者都不声明,或者都声明,这些情况都有可能。

InfoQ:Sealing 特性是否需要源码编译器的支持?

Goetz:Sealing 特性不仅仅需要编译器的支持,也需要 JVM 的支持,这样语言层面的约束——比如“X 不能继承 Y”——就可以在 JVM 层面得到加强。

InfoQ:Sealing 是否意味着“只能在当前模块内扩展出子类”?

Goetz:Sealing 可以有多种说法,最简单的就是“这个类只能在同一个源码文件中被扩展”——这是最常见的情况,也是最简单的。Sealing 也可以被定义成“同一个包中”或“同一个模块中”,甚至可以是“友联(friend)”或复杂的运行时判断。

InfoQ:Java 的新发布周期有助于模式匹配被集成到 Java 中吗?

Goetz:我们希望如此。我们已经将模式匹配分为几个小块,这样就可以快速地推出最简单的部分,然后继续开发其他部分。

InfoQ:什么时候可以看到原型?

Goetz:现在就有了,尝鲜者可以直接从源代码编译 JDK。“ Amber ”上有一个分支已经可以支持类型检测模式和“matches”判断谓语。

InfoQ:你们将会怎样继续关于模式匹配的研究工作?

Goetz:我们会继续探究如何将匹配器作为类成员,以及如何实现重载和继承。我们还有很多工作要做。

更多资源

查看英文原文: Brian Goetz Speaks to InfoQ on Pattern Matching for Java

公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2017-10-08 19:003119
用户头像

发布了 322 篇内容, 共 134.5 次阅读, 收获喜欢 144 次。

关注

评论

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

DevOps进阶(一):DevOps 软件开发工艺解读

No Silver Bullet

DevOps 2月月更

GIF 格式解析之表情包是如何动起来的

CRMEB

Linux系统编程-(pthread)线程通信(条件变量)

DS小龙哥

2月月更

移动办公时代,政企为何首选私有化的即时通讯平台?

WorkPlus

一站式交付体验:云效+Kubernetes

阿里云云效

阿里云 Kubernetes 云原生 持续交付 一站式平台

Kafka消息存储机制

编程江湖

IAST 最佳实践 | 利用洞态做开源组件的安全治理

火线安全

AMD EPYC服务器芯片将涨价10%~30%

WorkPlus

百度AICA再添57位“首席AI架构师”,人工智能与产业场景结合愈发深入

百度开发者中心

飞桨 百度AI

动态加载不适合数组类?那如何动态加载一个数组类?

华为云开发者联盟

Java 数组 动态加载 数组类

百度智能云开物再收“一个奖状”

百度开发者中心

工业互联网 百度智能云 百度智能云开物

Linux系统编程-(pthread)线程通信(读写锁)

DS小龙哥

2月月更

某 E-Office v9 任意文件上传【漏洞复现实战】

H

网络安全 漏洞

Linux系统编程-(pthread)线程通信(围栏机制)

DS小龙哥

2月月更 围栏机制

资讯|WebRTC M97 更新

网易云信

WebRTC

对话 SphereEx 创始人张亮:开源与商业并行 做时间越久越有价值的事情

SphereEx

会声会影如何制作视频影片-影片制作过程三步骤

懒得勤快

浪潮云说丨上云迁移实践

浪潮云

云计算,

像搭积木一样定制系统,这家公司正瞄准数据库做增值服务

SphereEx

程序员必知的8个Java开源IDE工具

编程江湖

ide

Linux系统编程-(pthread)线程通信(互斥锁)

DS小龙哥

互斥锁 2月月更

抓到Netty一个Bug,顺带来透彻地聊一下Netty是如何高效接收网络连接的

bin的技术小屋

网络编程 中间件 netty 死磕 NIO Java【

Linux系统编程-(pthread)线程创建与使用

DS小龙哥

线程 2月月更

四款你必须知道的前端开发工具

编程江湖

从小样本学习出发,奔向星辰大海

百度开发者中心

百度云 百度 飞桨

Java培训:封装的含义及实现方式

@零度

JAVA开发 封装

虎符交易所Hoo研究院:Open Sea上大火的NFT项目—Azuki

区块链前沿News

NFT Hoo 虎符交易所 Azuki

Linux系统-Makefile规则介绍、基本使用

DS小龙哥

Linux makefile 2月月更

成为第一没有捷径:AI新势力MindSpore成长秘籍 | 源创者说 专访胡晓曼

科技热闻

误删D盘数据怎么办?推荐使用数据恢复软件EasyRecovery

淋雨

数据恢复 EasyRecovery

Apsara Stack 技术百科 | 可运营的行业云,让云上资源跑起来

阿里云 科技 混合云

与Brian Goetz聊Java的模式匹配_Java_Michael Redlich_InfoQ精选文章