技术开发 频道

年度回顾:JavaSE 7值得期待之处

  【编者按】从2007年初开始,阿莱克斯·米勒(Alex Miller)一直在坚持关注Java SE 7中将包含的Java规范要求(JSR)的相关信息。在本篇年度回顾文章中,他与我们分享了他的收获:对这个即将到来的平台规范给出了最合理的描述,并向大家介绍了最近来自Sun公司的一些相关信息。通过这篇文章,我们可以了解Java SE 7中将最可能看到哪些改进,以及哪些JSR可能不会被包含在Java SE 7中。

  
阿莱克斯·米勒

  米勒是Terracotta公司的技术带头人,该公司的代表产品有开源Java群集应用Terracotta。在加盟Terracotta之前,米勒曾就职于BEA系统公司,主要研究AquaLoigic系列产品,并曾在MetaMatrix担任过首席架构师。

  【IT168 分析评论】当Java SE 6在2006年12月发布之后,开发者就已经立即开始关注哪些JSR有可能被包含在Java SE 7中。在2007年1月份,我开始就这个问题与业界同仁展开讨论,现在已经过去近两年的时间,当时的观点中有些被证明是正确的,也有一些已经被人们所逐渐淡忘。

  从成熟度、重要性和社区认可度等方面分析,现在我们或许可以更清楚的看到,哪些JSR和语言改进将有可能被包含在Java SE 7中。但是,在Sun公司Java SE首席架构师丹尼·考沃德(Danny Coward)正式提交Java SE 7平台JSR以前,一切变化都有可能发生。所有的Java类库和语言变化都将被作为平台JSR的一部分而被通过,新JSR与现有JSR共同组成新平台的完整功能集合。Java SE 7目前预计推出时间是2010年初。明年第一季度我们有望看到其平台JSR。

  本篇文章的其余部分,将重点介绍最有可能包含在Java SE 7中的功能,同时以代码示例来证明其相对于我们今天编程方式所带来的改变。我今天所介绍的所有JSR都具有详细说明和工作原型,因此它们已经相当成熟。

  更强大的依赖关系管理

  现在的Java程序员,或者说所有语言的程序员,都面临着日益增多的开源和商业类库,往往要花费很长时间来管理其依赖关系。今天的一个普通企业应用程序往往要依赖数十个外部JAR文件,其本身往往就能包含数十个不同团队开发的更小内部工程。我们一直在坚持寻找更好的方式来管理日益复杂的依赖关系,以使我们的开发更具重用性,部署更加完整。现在出现了越来越多的类似Maven的依赖关系管理系统,以及诸如OSGi之类的运行时部署系统,这一点正是反应了这种需求的增长趋势。

  在Java SE 7发展初期,两个重要的JSR曾经试图解决依赖关系管理问题,分别是JSR 294:Java编程语言中的改进模块性支持(Improved Modularity Support in the Java Programming Language)和JSR 277:Java模块系统(Java Module System),两者分别关注Java模块概念的开发和部署方面。一个模块(module)就是多个实现相同目标且相互存在联系的类的集合,与JAR类似,但是,根据开发和部署的需要,一个模块的范围可以是一个JAR的一部分,也可以是几个JAR的集合。在2008年中期,JSR 294被简化并合并到JSR 277中,以便同一个专家组能够先后研究这两个方面。

  在2008年12月份,Sun再次重新审视这一计划,宣布在OpenJDK社区中创建Jigsaw项目,以在明年实现JDK 7模块化。JSR 277和Java模块系统的研究将被放到Java SE 7推出之后进行,而JSR 294将被重新恢复研究。Sun已经声明了此举的意图是,与OSGi联盟更紧密的配合,以便JSR 294模块可以被OSGi所使用。

  Jigsaw项目和‘module’关键字

  在Java SE 7中有一个问题将得到解答,即Sun将如何来使用module关键字,它是最初的JSR 294中的一个重要概念,预计将包含在下一平台版本中。

  假定有一个名为Flapjack的项目由几个Java包(package)组成,该项目包含在基包(base package)中的一个public APIs,和实现这个API的几个内部包:

  ·org.flapjack - public API classes

  ·org.flapjack.impl - 实现类

  ·org.flapjack.util - 实用类

  在Java SE 6中,如果你需要在基包中放置一个工厂类(factory class),以实例化内部执行包中的API类,你需要将这个实现类设为public,这样它们才可以从API包中被看到。由于跨越了不同的包,没有办法既允许API以factory方法对类实例化,又不允许外部类直接执行它。

  JSR 294模块将允许你声明整个包集合为一个模块,你只需要在源程序中加入以下一个新的声明:

module org.flapjack;

  你可以将这个声明加在你的项目中每一个源程序文件中,也可以将其增加到package-info.java文件中,然后一次将其应用到整个包。虽然module是一个新关键字,它是一个“限制性”关键字,只有在特定位置时才被作为关键字来处理;因此,它可以在任何其它地方作为普通Java标识符来使用。这使得它扩展了语言的功能,同时又保持了其向后兼容性。

  除了新的声明外,你还可以把module关键字当作一个新的可见性修饰符使用,你可以用它来定义一个类,使其仅对同一个模块中的其它类可见,Listing 1演示了module关键字的这种用法。

  Listing 1

module org.flapjack;

  
package org.flapjack.impl;

  
import org.flapjack.Flapjack;

  module
class FlapjackImpl implements Flapjack {

  }

  最后,你可以定义一个新的module-info.java伪类,使用元数据来注释该模块,增加诸如版本、主类、导入的依赖模块、导出资源和许多其它预定义或特定的模块注释等。值得注意的是,与现有的package-info.java文件一样,这个新的module-info.java文件使用了一个无效Java源文件名称,可以避免与已经存在的文件可能发生冲突。

  在编译时,JSR 294让你可以使用javac来编译你的类。至于在JVM中,Jigsaw项目将如何规定模块的组成、加载和验证,尚需拭目以待。

  更多NIO APIs

  JSR 203:NIO 2扩展和实现了在Java 1.4中加入的最初NIO功能。在NIO 2中最明显的新增功能就是文件访问API的全面改进。多数开发者都用过java.io.File,对其存在的众多缺陷自然心中有数:

  ·不支持符号链接(symbolic links )

  ·不支持简单移动和拷贝操作

  ·目录漫游和过滤API非常复杂

  ·对文件属性和访问权限的支持非常有限

  ·没有查看目录或文件的API

  ·有限的错误处理功能

  幸运的是,JSR 203不仅改进了以上所有缺点,而且实现了更多功能。这个API从一开始就设计为具备可扩展性,除了支持默认文件系统外,还支持嵌入式文件系统,还具有诸多灵活选项设置,可以实现诸如打开和拷贝文件、系统属性定义等操作。

  Listing 2演示了JSR 203是如何被用来实现一些通用操作。Path是这个API的核心;你可以把它看作新建文件。

  Listing 2

import java.nio.file.*;

// FileSystems -> FileSystem -> Path
FileSystem fileSystem = FileSystems.getDefault();
Path homeDir
= fileSystem.getPath("/Users/lskywalker");

// Shortcut with Paths helper class
Path homeDir = Paths.get("/Users/lskywalker");
Path secrets
= homeDir.resolve("secrets.txt");
    
// Steal secrets
secrets.moveTo(Paths.get("/Users/dvader/secrets.txt"));

  除了文件系统API外,JSR 203还实现了许多在第一版NIO中提出的API,提供了对组播的更多支持,提供了在Socket和文件上进行异步I/O操作的API。

  解决时间间隔问题

  现有Java的Date和Calendar类一直都未能满足开发者的需要,一直都是开发者们的痛处。JSR 310:数据和时间API(Date and Time API)的目的就是提供一个完整的、功能齐备的Date和Time API。

  JSR 310日期/时间API试图通过提供更好的性能和易用性改进Java的当前日期/时间API。例如,Java Calendar类将日期同时存储为与标准纪元之间的偏移量(以毫秒为单位)以及一组日历字段(例如,星期几、几号以及月份)。此双精度表示导致在意外的时间重新计算日历字段,从而产生不可预测的性能特点。与此相比,JSR 310类仅将日期/时间表示存储为与Date和Calendar所使用的同一标准纪元之间的偏移量(以毫秒为单位);仅当需要时才会计算日期等日历字段,并且不会使用这些日历字段进行内部日期表示。

  JSR 310还对当前Java日期/时间模型进行了改进。Java 6 API不包含表示本地时间(不具有关联时区的时间)、持续时间或时间间隔的类。这迫使程序员使用令人困惑的设计做法,例如使用int表示持续时间。JSR 310包含表示上述各个概念的类,从而可以进行更为明确的程序设计。

  最后,JSR 310 API通过使用不可改变的类努力实现线程安全。Java当前的日期/时间类Date和Calendar都是可改变的,因而都不是线程安全的。

  更强的并行处理能力

  JSR 166y是一个修订版JSR,它带给我们J2SE 5.0中所有java.util.concurrent的优点,以及Java SE 6中的全部更新。JSR 166y中的主要新增功能,是一个叫做fork/join的新并行处理包。尤其值得一提的是,fork/join提供了对分而治之算法的支持。fork/join库的核心是一个叫做ForkJoinPool的新类和实现问题分解的一系列任务类型。

  多数典型应用一般不使用一个框架来解决计算密集型的分而治之算法。但是,JSR 166y还提供了一个新的功能式API,实现数组的并行处理。ParallelArray是一个可用于fork/join算法的数据结构,它提供了一个通用目的API,以高度并发的方式执行数据集的搜索、过滤和转换。其真正好处是,这些操作可以通过ForkJoinPool并行执行,在将来的多核计算时代,可以无需修改函数即可自动充分利用多核处理能力。至于ParalleArray是作为JDK的一部分包含在Java SE 7中,还是将作为一个外部库发布,现在尚处于考虑之中。

  Listing 3演示了如何使用ParalleArray来管理donuts的大量集合。

  Listing 3

// Instantiate the ForkJoinPool with a concurrency level

  ForkJoinPool fj
= new ForkJoinPool(16);

  Donut[] data
= ...

  ParallelArray donuts
= new ParallelArray(fj, data);

  
// Filter

  Ops.Predicate hasSprinkles
= new Ops.Predicate() {

  
public boolean op(Donut donut) {

  
return donut.hasSprinkles();

  }

  };

  
// Map from Donut -> Integer

  Ops.Predicate daysOld
= new Ops.ObjectToInt() {

  
public int op(Donut donut) {

  
return donut.age();

  }

  };

  SummaryStatistics summary
=

  orders.withFilter(hasSprinkles)

  .withMapping(daysOld)

  .summary();

  System.out.println(
"with sprinkles: " + summary.size());

  System.out.println(
"avg age: " + summary.average());

  J2SE 5.0中引入的并行功能和其在Java SE 6中的改进,为我们在4核或8核服务器上编写并行应用程序提供了坚实的基础。而fork/join库则又向前更深入了一步,可以支持更多处理器的应用程序编写,诸如未来几年中我们将使用的16核到32核计算机。它缓解了我们所面临的并行计算问题,但并未真正解决它。现在业界中的每一个人都在寻找可以利用多核世界进行编程的方法。尽管Java在此方面有一定领先优势,但共享状态的并发编程不可能在未来十年中都满足所有需求。Fork/join只是进一步的尝试。

  通过注释实现更好的决策

  J2SE把我们带入了Java注释的世界,在Java SE 6中,我们只可以对类、方法、字段和变量声明进行注释。JSR 308:Java类中的标注(Annotations on Java Types)允许注释出现在任何可用的类型上,使得更具表现力和准确性的系统成为可能。

  在JSR 305:供检查软件缺陷用的注解(Annotations for Software Defect Detection)中尽管定义了一些注释,但是JSR本身并不定义任何更多的注释。JSR 305的目的是让开发者更准确的定义方法调用情况,诸如是否允许为空,集合是否可以为空集合等等。

  Listing 4演示了如何使用一个新注释。

  Listing 4

// A more precise class definition:

  
class UnmodifiableList implements @Readonly List<@Readonly T> { ... }

  
// A more precise variable declaration:

  List str
= new @NonEmpty @Readonly ArrayList(stringSet);

  注释处理器可以被插入到编译器中,以在编译的时候验证这些注释。This allows a great deal more specificity and precision, but it comes with a heavy cost of verbosity and will certainly fill some Java users with dread.

  简化Swing

  与Swing相关的JSR正在上演三重唱。JSR 296:Swing应用程序框架,提供了个框架和多数Swing应用所需的功能,尤其是它提供了:

  ·定义良好的应用程序生命周期

  ·引入了更丰富的资源素材(诸如标签、字体和颜色等)

  ·行为管理(包括后退任务的支持)

  ·诸如Windows位置之类的持久性会话信息

  进入2008年以后,JSR 296一直处于巨大的生存危机中。尽管目前有复苏的迹象,但是许多人依然在怀疑它是否能在Java SE 7推出的时候证明自己。

  JSR 295:Beans绑定(Beans Binding)和JSR 303:Bean验证(Bean Validation),这两个JSR的目的是解决Swing应用程序中普遍存在的问题,不过它们也可以用于非Swing应用。JSR 303是一个可以为字段和类创建验证器的框架。这个JSR定义了一系列元注释,同时还定义了一些常见的约束性注释。

  Java管理扩展(JMX)更新

  JSR 255:JMX 2.0是JMX规范的一个全面升级,充分利用了J2SE 5.0中引入的语言特点,而且增加了一些重要的新功能,诸如命名空间、远程JMX服务器联盟、一个新事件服务和查询语言等。

  JSR 262:JMX的Web服务连接器(Web Services Connector for JMX),允许客户端通过Web服务连接到一个JMX MBean,它也支持非Java的Web服务客户端。

  语言变化或许较小

  鉴于目前距离Java SE 7推出的时间有限,增加重大新语言功能的可能性已经不大,在Java SE 7平台规范中只能包含一些细微的调整。Joseph Darcy将负责领导一个OpenJDK项目来收集和评价这些语言改变之处。

  闭包(Closure)是Java SE 7中最大的语言功能变化。闭包肯定将给这个语言带来重大的影响,本文中我所讨论的其它JSR也是如此。众多提议已经被提交,其中最重要的三个已经具有工作原型。尤其值得指出的是,Neal Gafter关于BGGA闭包的提议还包含了完整的规范和工作实现,它在现有提议中是最详细最完整的。

  鉴于Sun紧缩的资源和人力,以及重大JSR的数量,加上发布时间的压力,闭包被包含在Java SE 7中的可能性已经不大。在我看来,这是一件非常遗憾的事情,因为闭包可以大大简化NIO 2、fork/join和其它类库中的API。缺少了闭包功能的Java SE 7将丧失解决这些问题的机会。

  一些其它可能的小型语言改进包括:

  ·Strings可以用于switch中的case子句。

  ·比较运算符(<、>等)可以直接用于枚举常量。

  ·Chained invocation—空方法隐式返回这个信息

  ·扩展方法

  ·可一次捕获多种异常类型,以及并发形式rethrow特定类型异常。

  动态语言支持

  JSR 292:Java平台动态语言支持(Supporting Dynamically Typed Languages on the Java Platform),开始引入一个名为invokedynamic的新JVM指令,以更好的支持动态语言。John Rose已经使用这个JSR作为一个公式来进行了大量的JVM改进,可以大大提高JVM上所有语言的功能。

  这方面的工作研究在2008年9月举行的第一届JVM语言峰会上达到顶点,在这次峰会上讨论了诸如尾部调用优化(tail call optimization )和接口注入(interface injection)等功能。对于大量使用递归的函数语言来说,尾部调用优化非常重要,可以避免堆栈空间溢出,Scala在编译器上解决了这个问题。Clojure则增加了模仿尾部调用的语言支持,而且最近增加了跳跃语言支持功能,以支持多重递归。如果尾部调用优化可以被增加到JVM中,Scala和Clojure可以简化或移除这些功能。

  Mark Reinhold在JVM语言峰会上表示,JSR 292将被包含在Java SE 7中。在JSR 292是否还包含invokedynamic之外的任何功能,目前还不确定。

  Java SE 7和Java未来

  我相信在2009年可以看到Java SE 7平台JSR,它将包含本篇文章所讨论的多数JSR,但是语言本身的改变可能会比较少。按现在的计划,它将继续集成所有这些工作到OpenJDK版本中,并在2010年发布Java SE 7。

  有些人质疑人们是否真的需要使用Java SE 7。不过,即使出现很多替代性的JVM语言,Java依然将会是我们今天所使用的重要编程语言之一。Java拥有如此巨大的用户基础,在目前还看不到被淘汰的迹象。诸如294、310和203等JSR对核心API进行了改进,这些对于企业软件开发者都是非常值得关注的。同时,我们现在正在进入多核时代,JSR 166和JVM性能的改进也是颇具吸引力的。

  我认为,Java SE 7的普及速度或许不会很快,但却会稳步上升。如果这个平台在2010年初发布,有望在2011年获得可观的市场份额。在Java SE 6发生的一幕或将在它身上重演。J2SE 1.4在2008年11月份已经结束了服务支持周期,J2SE 5.0将在2009年底加入支持范围。届时,多数进行Java应用部署的企业都将考虑在Java SE 6上的部署。按现在的情况来看,如果Java SE 7语言变化非常小,许多企业甚至有可能跳过J2SE 5.0而直接升级到Java SE 7。

  查看原文:http://www.javaworld.com/javaworld/jw-12-2008/jw-12-year-in-review-2.html

0
相关文章