原标题:初试Java9
Java 9 正式发布了
JDK 9
(http://openjdk.java.net/projects/jdk9/)
有不少重要或是有意思的新特性,这里简单介绍下我的了解与尝试
抛砖引玉
下载
oracle 官网下载即可。
(http://www.oracle.com/technetwork/java/javase/downloads/jdk9-downloads-3848520.html)
安装配置好之后, java -version 查看一下, 会看到
这里正有一个新特性[223], 新的版本字符串格式$MAJOR.$MINOR.$SECURITY.$PATCH.
值得一提的是,Java 9 以后,新的功能版本将每六个月更新一次, 每三年发布一次长期支持. 此外,下个版本并不是 Java 10,而是Java 18.3,将于2018年3月推出。
新特性
jigsaw 模块化
可以说Java 9 最重要,也是受到最多关注的功能就是模块化了。模块化经历了多次跳票,带来的改变也是巨大的。
首先,模块化是一种将程序实现为多个独立模块的方式,有助于降低系统的复杂性以及低耦合。
为什么需要模块化呢,jigsaw 的项目描述里写的很清晰:
使开发人员更容易构建和维护库和大型应用
提高安全性,可维护性
提高性能
可轻量级部署,以用于小型计算设备和密集云部署
相关介绍我们结合对应的JEP来看:
[261] 模块系统
实现了Java平台模块系统,以及相关JDK的特定更改和增强。
[200] 模块化JDK
Java9将JDK也分为一堆模块,可以在编译, 构建及运行时按照各种配置来组合。包括并不限于:
- 完整的JAVA SE平台,完整的JRE及JDK 的配置;
- 与在Java SE 8中定义过的"紧凑型配置"(Compact Profiles) 在内容上基本一致的配置;
- 或者是 仅包含 应用模块, 外部库 以及它们所需要模块的自定义配置。
JDK 自身的模块化,使得用户可以根据需要选择模块。小型设备上可以不必要运行完整的JDK,简单的应用不再必须加载几十兆的 rt.jar, 后端应用也可以舍去并用不到的 Swing 等UI模块, 这使JAVA可以不那么臃肿。
[201] 模块化源代码
将JDK源代码重组为模块, 增强构建系统以编译模块
[220] 模块化运行时镜像(Run-Time Images)
重组JDK和JRE运行时镜像以适应模块,并提高性能, 安全性以及可维护性。定义新的URI方案,用于命名存储在运行时镜像中的模块,类和资源,而不会透露镜像的内部结构或格式。并根据需要修改现有规范以适应这些变化。
[260] 封装大多数内部API
默认封装JDK大部分内部API,使其在编译时无法访问。并为后面的发行版做准备,使其在运行时也无法访问。同时确保关键的,被广泛使用的内部API不被封装,以便它们仍可用,直到大部分功能都能被替换为止。
这就涉及模块化的另一个特点了, 强封装。
[275] 模块化Java应用程序打包
[282] jlink
在编译和运行之间 引入了一个新的可选阶段-链接,可以用 jlink 将一堆模块及其依赖项组合并优化到自定义运行时镜像中。
举个例子,假如我们写了一个简单的 helloWorld 的程序,只用到了 java.base 模块。 就可以指定模块打包:
output 里会得到一个完整可用的仅包含 java.base, 也就是基础模块的jre。同样,我们也可以将自己的模块一起打包。具体例子稍后给出。
Java 9 模块之间的依赖关系图
Java9 中,我们是通过 module-info.java 来定义并管理模块,指定模块之间的依赖关系的。默认包含基础模块 java.base。 这里举例 java.sql 模块的 module-info.java文件:
很容易看到这里和依赖关系图里是一致的,java.sql 直接依赖了 java.xml 与 java.logging 两个模块。
在该 module-info.java 文件中, module 后面的 "java.sql" 即定义的当前模块名。
requires ; 表示当前模块A 依赖于另一个模块B 。 transitive 修饰符表示, 如果有模块依赖于A,则隐含地依赖B。
exports ; 表示当前模块A 导出指定的 P包。 需要用到的模块C 只需要 require A即可。也可以使用 (exports to ;) 来指定导出模块,这样的话对于C 以外的模块来说,P 是不可见的。
可以看出,requires 是模块级别, exports 则具体到包。编写模块的人可以很细致的管理以及限定真正想要导出的内容。[260]里提到的正是这种情况, 像 sun.*, .internal. 等并不提倡使用, 就可以将这种API 指定只导出到用到的基础模块。
此外, 还支持服务提供者与使用者分离的机制。
uses ;
provides with , ...;
provides 提供服务接口的一个或多个实现类。 uses 指定服务接口, 然后当前模块就可以使用 ServiceLoader 类进行加载。
参考官方文档给出模块化的一个简单示例。
首先代码很简单,这里共4个文件, 两个模块, org.astro 与 com.greetings.
然后编译及打包。
注: -p 同 --module-path, 是模块路径, 可以是包含模块的一个或多个目录。 -m 选项指定主模块,斜杠之后的值是模块中主类名。
jshell [222]
这是一个相当受欢迎的新功能。命令行直接输入 jshell 就可以开始使用,可以作为随手运行各种小代码的工具, 非常方便。
tab 可以自动补全,可以忽略句尾分号。输入 /exit 或Ctrl+D 即可退出。
HTTP/2 Client [110]
定义了新的HTTP client API,支持 HTTP/2及WebSocket,可以替换掉原有的HttpURLConnection。 不过相关的 API 放在了 jdk.incubator.http 下,而不在默认模块里,也就是使用时需要在 module-info 里加上 requires jdk.incubator.httpclient;
Milling Project Coin [213] 一些小变化
@SafeArgs 注解之前只能用于static及final方法,现在也可用于私有实例方法。
try-with-resources 之前资源的声明语句放在 try 关键字的括号里面,现在支持 effectively-final 变量。
只要编译器能推断出类型参数, 匿名类允许使用<>
下划线 _ 不能单独用做标识符。
interface 之前已经支持添加默认方法, 现在支持私有方法。
紧凑型字符串 [254]
String 采取更加节省空间的内部表示,提高了空间效率,同时保持大多数情况下的性能,并完全兼容原有接口。
从 char[] 改为使用byte[],直接存放编码。在构造时设置 LATIN1 或者 UTF16。省内存!
集合工厂方法[269]
Map/Set/List接口添加了简单初始化不可变集合的工厂方法, 可以直接写作如 List.of(1, 2, 3),不再需要挨个元素来 add 了。返回的是 java.util.ImmutableCollections 下定义的嵌套类型的实例, 注意,是不可变的集合。
总而言之,JAVA 9 的新特性还有很多,比如: 更新了进程相关接口(可以直接获取 pid! )[102], 统一JVM日志[158],增强javadoc支持HTML5[224], javadoc 页面终于加上了搜索条:) [225], 缺省GC 改为 G1 [248] , 实现SHA-3加密散列函数[287], 等等。
这里就不一一列举了, 期待大家进行更深入的研究与分享。
备注
文中提到的链接:
JDK 9 新特性
http://openjdk.java.net/projects/jdk9/
JDK 9 下载链接
http://www.oracle.com/technetwork/java/javase/downloads/jdk9-downloads-3848520.html
JDK 18.3 项目链接
http://openjdk.java.net/projects/jdk/18.3/
jigsaw 项目链接
http://openjdk.java.net/projects/jigsaw/
模块依赖关系图
https://bugs.openjdk.java.net/secure/attachment/72525/jdk.png
责任编辑: