`
sunxboy
  • 浏览: 2869066 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

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

阅读更多

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平台推向新的远方。

 

 

 

分享到:
评论

相关推荐

    JAVA 反编译器

    9. **反编译器的未来**:随着Java语言和JVM的不断演进,反编译器也在不断发展以支持新的特性,如Lambda表达式和模块系统。开发者可以期待更准确的反编译结果和更好的用户体验。 总的来说,Java反编译器是开发工具箱...

    JDK1.8(Java Development Kit)是 Java 语言的软件开发工具包

    这种改变使得接口可以在不破坏现有实现的情况下添加新的功能,为接口演进提供了便利。 5. **Date与Time API的改进**:JDK1.8对日期和时间API进行了彻底改革,引入了`java.time`包,提供了更强大、更易于使用的日期...

    java基础技术介绍,比如数据类型,语法等等

    随着Java技术的不断演进,Java也逐渐应用于移动设备开发(如Android系统)、企业级应用(如Java EE平台)和大数据处理(如Hadoop框架)。它的广泛适应性、强大的库支持和社区活跃度使其成为了IT行业中的重要组成部分...

    让Java EE再次变酷使用JPA和EJB构建基于MongoDB的网络服务

    Hibernate OGM使得开发者能够在不改变现有JPA/EJB代码的情况下,无缝地切换到MongoDB这样的NoSQL数据库。 #### 软件架构 本文提出的软件架构主要包括以下几个关键组件: 1. **Java EE应用程序**:包含业务逻辑和...

    java设计 原则61条

    在第77页中提到,构建系统时应当逐步推进,避免一次性实现所有的功能,这样可以在实施过程中不断调整和完善设计方案。 **原则40:合理处理单例模式** 在第77页中进一步指出,当使用单例模式时,应当合理地处理单例...

    深入理解Android(二):Java虚拟机Dalvik

    Xposed框架利用了Dalvik虚拟机的特性,能够在不修改APK文件的情况下改变程序的行为。它通过注入代码的方式,在应用程序运行时修改其行为,从而实现了许多高级功能。要深入了解Xposed的实现原理,就必须掌握Dalvik...

    java script

    - AJAX允许不刷新整个页面的情况下与服务器交换数据并更新部分网页内容。 - `XMLHttpRequest`对象是实现AJAX的核心,现代浏览器还提供了更简洁的`fetch` API。 6. **闭包(Closures)** - 闭包是JavaScript中一...

    中文API(Java 8).zip

    5. **Optional类**:`Optional<T>`是Java 8新增的一个容器类,用于表示一个值可能存在也可能不存在的情况。这有助于避免空指针异常,并鼓励开发者明确处理null值。 6. **Method References**:除了Lambda表达式,...

    jdk1.7.0_65

    - `JDK 1.7.0_65`保持了与早期版本的兼容性,允许开发者在不改变大量代码的情况下升级到新版本。 总结起来,`JDK 1.7.0_65`作为Java开发的核心组件,其重要性在于它提供了一个稳定的平台,支持开发者利用最新的...

    重构模式.rar

    重构是提升代码质量、可读性和维护性的重要手段,它涉及在不改变软件外部行为的前提下,改善其内部结构。这本书详细阐述了重构过程中的一系列模式,帮助开发者更好地理解和实践重构。 在面向对象编程中,重构通常是...

    jdkapi1.8.rar

    在Java 1.6和1.8版本之间,有许多重要的改变和改进,这些变化反映了Java语言的发展和现代化趋势。下面我们将深入探讨这两个版本的API差异,并了解它们如何影响Java编程。 首先,让我们从Java 1.6 API开始。这个版本...

    [Js]JavaScript语言参考中文版.zip

    Ajax(异步JavaScript和XML)技术允许在不刷新整个页面的情况下更新部分网页内容,提高了用户体验。 JavaScript还有许多重要的库和框架,例如jQuery简化了DOM操作和事件处理,React.js和Vue.js用于构建用户界面,...

    面向对象编程简史

    Java语言的设计考虑到嵌入式系统的特点,如资源限制和高可靠性需求,避免了指针和goto语句等易引发错误的结构,强化了异常处理机制,确保程序能够在面对意外情况时依然保持稳定。尽管最初并未在消费电子领域取得成功...

    Hibernate4.0

    然而,这也意味着在低于Java 1.6的环境(如Java 1.5)下运行Hibernate 4.0将面临一系列的问题,例如`UnsupportedClassVersionError`异常,这是因为类文件版本不匹配导致的。 当尝试在Java 1.5环境下运行Hibernate ...

    Developing International Software

    它涉及在不改变产品代码的情况下,使产品能够适应不同的语言和文化习惯。本文将基于微软出版的《Developing International Software》一书的部分内容,探讨国际化软件开发的关键概念和技术。 #### 二、国际化与本地...

Global site tag (gtag.js) - Google Analytics