写点什么

在不改变语言的前提下如何推进 Java 的不断演进

  • 2010-03-16
  • 本文字数:4528 字

    阅读完需:约 15 分钟

James Gosling 在“ The Feel of Java ”中说到:

Java 是一种蓝领语言,它并非博士的论文素材而是用于完成工作的语言。各式各样的程序员都非常熟悉 Java,因为在设计 Java 之初我就坚持这样一种观点:选择久经考验的东西而非仅仅是听起来很美。

Java 所获得的巨大成功证明了这种设计方式是正确的,但如果这依然是当今 Java 的重要目标的话,那么其结果就是语言的演进将变得非常缓慢。除此以 外,Java 是一门成熟、使用广泛的语言这个事实也将导致其演进过程充满了困难。一方面,添加到语言中的每个特性都可能在一定程度上造成不可预料的结果, 这么做会疏远那些已经使用了该语言的开发者。另一方面,本身很完美的特性可能在同语言中的其他特性进行交互时产生不可预料的结果。更糟的是,一旦增加了某 个语言特性,几乎就不可能再将其移除了,即便是该特性会对整个语言产生不利影响也没办法。为了证明某个新特性是正确的,语言设计者必须确信从长远来看,该 特性会给语言带来好处,而不是短期效益或是针对某个问题的快速解决方案,之后就变得可有可无了。为了降低风险,语言设计者通常都会创建单独的一种语言或是 分支来进行试验,比如 Pizza 语言就是在实现前用来测试 Java 泛型的。这种方式的问题在于试验的参与者非常小众并且都是自己想参与进来的;显然他们对 语言特性很感兴趣,很多人都是学者或研究员。但是,在普通的程序员开始使用这些特性时,那些学者或是研究员认为很棒的特性可能会变得很糟。

为了直观感受一下这种情况,请考虑关于 Java 7 闭包特性的激烈争论。一段时间以来,有人在提案中给出了闭包的实现,但最终却还是没有达成共识。随后,Sun 决定不打算在 JDK 7 中添加完整的闭包支持。这时争论的焦点转向为 Java 是否变得越来越复杂了,在 Java 5 中添加泛型(尤其是通配符语法)时就已经出现了这种争论;在 Java 已经通过匿名内部类部分实现该功能的情况下,完整的闭包支持是否是正确的呢。需要完 整闭包支持的两个重要场景是简化 fork/join API(添加到了 JDK 7 中以改进多核编程)的使用以及辅助资源的清理。Josh Bloch 的 ARM block 提案(期望通过 Project Coin 加入到 JDK 7 中)就第二个问题给出了另一种解决方案。Cliff Click 博士在面向 Java 的可扩展、非阻塞编程风格的研究中给出了关于fork/join 的另一种方案,随着处理器核心数的不断增 加,这种方案看起来更合理。如果这一切都成为可能的话,那么Java 中使用闭包的地方将变得非常少了,语言根本没必要提供这个特性。

话虽如此,但对于编程语言来说,持续不断地平稳发展还是非常重要的。因此本文探究了如下3 种技术以向Java 中增加新的语言特性而又不改变语言本身,他们 是客户化领域特定语言(DSL)、Java 6 的注解处理器(通过库来增加可选的语言特性)以及将语法糖从语言迁移到IDE 中。每项技术都可以让众多的主流开发者以非侵入的方式体验这些新特性,最棒 的想法则可以融入到语言核心当中。

客户化DSL

在这3 项技术中,人们谈论最多的还是 DSL 。该术语的确切含义至今尚未统一,但出于讨论的目的,我们在这里简单地把它看作是用于解决特定问题、应用范围很窄 的一种语言而非用于解决所有计算问题的通用语言。这样,DSL 就并非是图灵完备(non-Turing complete)的。当然了,还是会有一些边际情况存在的,比如说 Postscript 是一种图灵完备的语言, 但根据我们方才的定义,它也是一种 DSL。

如上所述,DSL 并非新概念。其他类似的 DSL 还有正则表达式、XSLT、Ant 以及 JSP 等等,所有这些都需要某种客户化的解析器对其进行处理。 Martin Fowler 还说fluent interfaces/API 也可以看作是另一种 DSL,称之为内部 DSL。他说内部 DSL 是直接在宿主语言中开发出来的。这对于 Lisp 和 Smalltalk 开发者来说很容易理解,而最近 Ruby 社区也开始对内部 DSL 情有独钟了。

虽然很多知名的 DSL 都是由商业公司开发和维护的,但一些企业开发团队也已经使用该技术来创建能够快速解决其问题的语言了,但毕竟还是小众,这可能是 DSL 领域门槛比较高的缘故吧。负责 DSL 的团队必须要设计语言、构建解析器和其他工具来支持开发团队,还要对每个新员工进行培训,让其了解 DSL 的工作 机理。这时,涌现出了能够支援 DSL 开发的工具,这极大地改变了当前的状况。Intentional Software 所开发的 Intentional Domain Workbench 比 Java 还要久远,它首度实现了该工具的功能。该项目创建于微软研究院,Charles Simonyi 博士在 1995 年所发表的论文“ The Death of Computer Languages, the Birth of Intentional Programming ”描 绘了其愿景。2002 年,Simonyi 创建了 Intentional Software 以继续实现其想法,大家可以看看介绍该系统的视频,极具震撼力。目前该产品的版本是1.0,但只有极少数的合作者能够访问。

其他一些软件公司也在研究这个概念,其中就包括以 IntelliJ IDEA Java IDE 而扬名天下的 JetBrains,JetBrains 最近发布了 Meta Programming System(MPS)1.0 版。MPS 并没有使用解析器而是直接使用了 Abstract Syntax Tree(AST)。它提供了一个类似于文本的投影编辑器(projectional editor)以便程序员能够操纵 AST,同时该编辑器也可用于编写语言和程序。当程序员使用投影时就会为树上的每个节点创建一个文本投影,这样变换就会 反映到节点当中。开发者可以通过这种方式以任意组合(通常称之为语言组合)扩展和嵌入语言。JetBrains 正在内部使用该产品,最近发布的 bug 追踪 产品 YouTrack 就是使用该系统开发的。

Java 6 注解处理器

相对于 Ruby、Smalltalk 和 Lisp 来说,DSL 在很多主流语言(如 Java)中的流行程度就稍逊一筹了,但最近 Java 语言的一些变化(尤其 是 Java 6 中新增的注解处理器)为开发者提供了新的机遇以在其中使用 DSL。对于 Java EE 6 中的 JPA 2.0 来说,其某些 API 本身就是 DSL。注解处理器会为应用中的每个持久化类建立一个元模型类型(metamodel type)。虽然开发者可以手工处理 Java 中的元模型,但这实在太无聊而且极易出错。注解处理器的出现改变了这一切,因为它内建于 Java 6,因此无需特殊的 IDE 支持——IDE 会代理编译器所触发的注解处理器,之后会自动生成元数据模型。

程序库也可以通过注解处理器来提供新的语言特性。比如说,Bruce Chapman 的原型“no closures”提案就凭借该技术将方法转换为 Single Abstract Method(SAM)类型,然后在 Java 6 上编译。在与其交谈过程中,Chapman 指出 SAM 类型还支持自由变量(free variable),这是闭包的一个关键技术:

除了 Single Abstract Method 所需的参数外,方法体还可以通过 @As.Additional 注解声明额外的参数。在获得 SAM 类型的实例时,这些参数可以带有绑定值,然后 在每次调用时传递给方法。

Chapman 还创建了 Rapt 项目以探索该技术的其他使用场景,同时为语言的两个变化提供了自己的实现——多行字符串(Multiline Strings) XML 字面值(XML literals)——这两个特性是 为 JDK 7 准备的,但却不会包含到最终的发布中。Java 甚至也可以使用这种方法实现闭包,Chapman 对此说到:

我们刚刚使用该技术完成了一个 Swing 项目,在这个过程中发现了泛型的一些小 bug,其中一个 bug 还没有修复,除此之外一切都很棒,没人再想使用传统 的匿名内部类了。

另一个探究注解处理器的项目是 Lombok ,它将该技术又向前推进了一大步。Lombok 将注解作为回调以运行 Java agent,后者会根据注解重写各种 javac 内核。由于操纵的是内部类,因此它不太适合于产品使用(JVM 各个小版本中的内部类也可能不一样),但该项 目对于注解处理器到底能做什么这个问题上还是颇具启发意义的,包括:

  • 通过 @Getter 和 @Setter 注解定义各种访问级别的属性,如 @Setter(AccessLevel.PROTECTED) private String name;
  • @EqualsAndHashCode 注解会根据对象中的属性实现 hashCode() 和 equals() 方法
  • @ToString 注解会实现 toString() 方法
  • @data 方法相当于 @ToString、@EqualsAndHashCode、所有属性的 @Getter 以及所有非 final 属性的 @Setter 的集合,可以使用 @data 方法和构造方法初始化 final 属性

还可以通过这种方式进行其他的语言试验,比如移除 Java 中的非运行时异常等。

虽然注解处理器技术为语言试验开辟了一条新航线,但还是要注意生成代码的可读性,保证开发者能读懂生成的代码。Chapman 给出了很多建议:

要生成源代码而不是字节码,注意生成代码的格式(尤其是缩进)。编译器不在乎生成的代码是不是都在同一行,但用户在乎。我甚至还使用注解处理器在恰当的地方增加了一些注释和 javadoc。

如果这项技术逐渐流行起来,用户将可以通过 IDE 查看编译期所生成的代码。

IDE 中的语法糖

Bruce Chapman 还提到了第三项技术——将语法糖从语言迁移到 IDE 中——他在博客中对该问题做过深入阐述。对于 Java IDE 来说,生成部分样板代码已成为不可或缺的功能了,比如类的 getters 和 setters,但 IDE 开发者刚刚开始深挖该这个概念。 JetBrains 的 IntelliJ 9为内部类提供了一个类似于闭包的简洁的代码块语法,开 发者也可以自己加。就像代码折叠一样,该语法会扩展到编译器能够处理的完整的匿名内部类——这样坚持使用标准的匿名内部类语法的开发者很容易就适应了。 Eclipse 也有一个类似的插件。关键在于这种语法仅仅是实际代码的另一种展示方式而已,编译器和任何源代码管理工具都能够像以前那样处 理他们。开发者可以在两种方式间自由切换(就像代码的展开与收起一样),无权访问该语法糖定义的人仅仅会看到正常的 Java 代码。Chapman说到

要想实现易于使用的目标还有很多工作要做,但从长远来看,我发现开发者会很轻松地实现加糖 / 脱糖(sugaring/desugaring)的转换(可以 参考 jackpot 来 了解实现原理)、不断尝试、不断演进并与同事和社区分享好的点子。这么做的好处与语言的演进别无二致。最好的东西会流行起来并形成实际语言演进的基础,如 果必要的话还可以随时去除该方法无法实现的“噪音”。

由于语法糖还要兼顾(非常多)其他的语言特性,因此无法提供完整的闭包支持;比如说 BGGA 闭包就有一些特性无法匹配匿名内部类,因此不能通过这种方式实现。话虽如此,这种想 法却展示了通过各种新语法来表示匿名内部类的可行性,类似于 BGGA 语法或是 FCM 语法,开发者也可以选择自己喜欢的语法。其他的语言特性(如 null-safe Elvis operator )可以通过这种方式实现。要想进一步验证该想法,可以体验一下这个 NetBeans module (由 Chapman 开发),这正是他所说的用于 Properties 的原型。

结论

在语言的发展过程中总是需要考虑稳定与发展之间的平衡。上面介绍的技术所带来的好处是他们不会影响平台或是语言本身。这么做允许我们犯错误,也有益于进行 快速激进的试验。由于开发者能够自由地进行试验,我们看到越来越多的人开始解决常见的样板代码“噪音”问题,如匿名内部类语法等,同时将这些想法以合理的 方式组织起来以获得最大的价值。我们将欣喜地看到开发者使用这些方法将 Java 平台推向新的远方。

查看英文原文: Evolving Java Without Changing the Language


给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2010-03-16 07:284830
用户头像

发布了 88 篇内容, 共 263.1 次阅读, 收获喜欢 8 次。

关注

评论

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

赴一场AI星河之约:他们改变了什么?

脑极体

AI

KaiwuDB 受邀亮相“ACDU 中国行”数据库技术沙龙(西安站)

KaiwuDB

KaiwuDB ACDB 中国行

好用的英语学习工具:Eudic欧路词典增强激活版中文

mac大玩家j

翻译软件 Mac软件 翻译工具

语音数据集:智能语音技术的燃料与推动力

来自四九城儿

GLTF编辑器实现逼真的石门模型

3D建模设计

WebGL 3D渲染 three.js 材质纹理贴图 3D材质编辑

家页观察丨万华生态绿色化、工业化、数字化助力城市更新

Geek_2d6073

GLTF编辑器-位移贴图实现破碎的路面

3D建模设计

WebGL 3D渲染 three.js 材质纹理贴图 3D材质编辑

LLM评估:通过7大指标监测并评估大语言模型的表现

Baihai IDP

程序员 AI ChatGPT LLM 白海科技

百度CTO王海峰:文心一言用户规模破1亿

飞桨PaddlePaddle

人工智能 深度学习 WAVE SUMMIT

基于大数据、大模型的应用总结与技术心得

joe

西部市场的无限潜力与成都的崛起“2024成都电子信息展会”

AIOTE智博会

电子展 电子信息展 成都电子展

重庆中烟:事项会计驱动业财深度融合

用友BIP

业财融合

写实风格3D模型材质贴图

3D建模设计

WebGL 3D渲染 three.js 材质纹理贴图 3D材质编辑

坚果的2023年终总结-激流勇进的一年

坚果

年终总结 坚果派

AI大模型时代下运维开发探索第二篇:基于大模型(LLM)的数据仓库

阿里云大数据AI技术

Linux操作系统中软件安装:用RPM包管理器安装软件步骤

小魏写代码

“边缘计算:从概念到实践的探索与思考“

future

语音数据集:开启智能语音技术的新篇章

来自四九城儿

3D 渲染如何帮助电商促进销售?

3D建模设计

WebGL 3D渲染 three.js 材质纹理贴图 3D材质编辑

GLTF 编辑器实现逼真3D动物毛发效果

3D建模设计

WebGL 3D渲染 three.js 材质纹理贴图 3D材质编辑

江铃晶马 X 袋鼠云:搭建企业级数据资产中心,推进打造“智数晶马”

袋鼠云数栈

大数据 数据中台 数字化转型 案例 大数据平台

taobao.trade.memo.update( 修改交易备注 )丨淘宝店铺订单接口

tbapi

淘宝店铺订单接口 天猫店铺订单接口 淘宝店铺订单交易接口 淘宝店铺订单备注接口 天猫订单备注接口

爆红的PLM!

用友BIP

PLM

避坑指南之财务共享服务中心的质量管理

用友BIP

财务共享

来聊聊程序员的职业发展路线

伤感汤姆布利柏

强大的磁盘分析:Disk Xray最新激活版

胖墩儿不胖y

Mac软件 磁盘分析软件 磁盘工具

IM通讯协议专题学习(十):初识 Thrift 序列化协议

JackJiang

网络编程 即时通讯 IM

有了向量数据库,我们还需要 SQL 数据库吗?

Zilliz

sql 向量数据库 zillizcloud rag

观测云产品更新 | 智能监控、应用性能监测、场景图表等优化

观测云

APM 智能监控

语音数据集:推动人工智能语音技术的关键要素

来自四九城儿

云原生与持续交付:加速软件交付与部署的革命

范艺笙冉

在不改变语言的前提下如何推进Java的不断演进_Java_Charles Humble_InfoQ精选文章