【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

与 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:003112
用户头像

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

关注

评论

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

抖音打击仿冒热点事件帐号行为:如何打击平台上的山寨账号

石头IT视角

焱融看|非结构化数据场景下,数据湖到底有多香?

焱融科技

数据湖 文件存储 非结构化数据 分布式文件存储 分布式文件系统

M_7: 王者荣耀商城异地多活架构设计

Jadedev

架构训练营

LabVIEW控制Arduino驱动数码管(基础篇—11)

不脱发的程序猿

单片机 LabVIEW LIAT Arduino Uno 驱动数码管

Serverless Job——传统任务新变革

阿里巴巴云原生

阿里云 Serverless 云原生 Job

隔空手势交互,如何在现实世界上演“得心应手”?

阿里云视频云

计算机视觉 音视频 视频云

时间都去哪了

Teobler

研发效能 软件质量 团队效率 研发速率

CorelDRAW2022安装步骤及序列号

茶色酒

cdr2022

CompositePattern-组合模式

梁歪歪 ♚

设计模式

Typora+PicGo+阿里云OSS配置低成本图床

DS小龙哥

6月月更

最好用的 5 个 React select 多选下拉菜单组件测评推荐

蒋川

低代码 开发工具 React 组件 tab

阿里云发布性能测试 PTS 2.0:低成本、高效率、多场景压测,业务稳定性保障利器

阿里巴巴云原生

阿里云 云原生 性能压测 PTS

手把手推导分布式矩阵乘的最优并行策略

OneFlow

模型 教程分享 分布式矩阵乘 数据并行

git代码管理可视化工具 :Sourcetree(mac环境)

简单猿

macos git 工具 代码管理

C/C++ 单元自动化测试解决方案实践

vivo互联网技术

c c++ 自动化测试

融云互动游戏 SDK, 丰富娱乐玩法,「破冰」陌生人社交

融云 RongCloud

趣步运动挖矿系统开发,dapp模式定制

开发微hkkf5566

泰山众筹代币燃烧模式dapp系统开发逻辑分析

开发微hkkf5566

浅拷贝、深拷贝

源字节1号

软件开发 前端开发 后端开发 小程序开发

MYSQL 几个常用命令使用

CRMEB

2.6 从控制台加载航线图文件

Geek_古藤模根

图数据库 gremlin 入门

FlyweightPattern-享元模式

梁歪歪 ♚

设计模式

TDengine 2.6 正式发布,新增大量计算函数

TDengine

数据库 tdengine 物联网

听说你写sql很溜,一条sql查询语句是如何执行的?

简单猿

sql 流程 查询 MySQL 数据库

BridgePattern-桥接模式

梁歪歪 ♚

设计模式

当 diesel 遇见 jsonb

伍思默

Android技术分享| 利用Kotlin协程,多任务并行,测试RTM SDK性能

anyRTC开发者

android kotlin IM 移动开发 实时消息

那篇千猫图爬虫竟被反爬了,今日复盘解决一下,Python爬虫120例

梦想橡皮擦

6月月更

知识库对于企业有什么意义

小炮

成为零代码布道者,推广明道云获取奖励

明道云

并发编程从入门到放弃系列开始和结束

艾小仙

Java 并发编程 多线程 异步

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