JDK9 新特性 (二)

在上一篇的文章我记述了 JDK9 的两个最重要的特性:一个是模块化,一个是 jShell。另外就是 String 底层存储结构和 StreamAPI 的一些改动与优化。本次要记述主要的特性是全新的多分辨率图像 API、全新的 HTTP 客户端 API(其实是借鉴 OkHTTP 的框架,或者说是整合吧)、Deprecated 相关 API、智能 Java 编译工具与动态编译器、统一的 JVM 日志系统、javadoc 对 H5 的支持、JavaScript 引擎升级:Nashorn。然后再谈谈 JDK9 还需要什么吧,也就是对未来 Java 的展望。

多分辨率图像 API

在 Mac 上,JDK 已经支持视网膜显示,但在 Linux 和 Windows 上,并没有支持。Java 程序在当前的高分辨率屏幕上可能看起来很小,不能使用它们。这是因为像素用于这些系统的大小计算(无论像素实际有多大)。毕竟,高分辨率显示器的有效部分是像素非常小。

JEP 263 以这样的方式扩展了 JDK,即 Windows 和 Linux 也考虑到像素的大小。为此,使用比现在更多的现代 API:Direct2D for Windows 和 GTK+,而不是 Xlib for Linux。图形,窗口和文本由此自动缩放。JEP 251 还提供处理多分辨率图像的能力,即包含不同分辨率的相同图像的文件。根据屏幕的 DPI 度量,然后以适当的分辨率使用图像。

  • 新的 API 定义在 java.awt.image 包下
  • 将不同分辨率的图像封装到一张(多分辨率的)图像中,作为它的变体
  • 获取这个图像的所有变体
  • 获取特定分辨率的图像变体 - 表示一张已知分辨率单位为 DPI 的特定尺寸大小的逻辑图像,并且这张图像是最佳的变体。
  • 基于当前屏幕分辨率大小和运用的图像转换算法,java.awt.Graphics 类可以从接口 MultiResolutionImage 获取所需的变体。
  • MultiResolutionImage 的基础实现是 java.awt.image.BaseMultiResolutionImage。

全新的 HTTP 客户端

http://openjdk.java.net/jeps/110 ,这个是改动说明文档。2015 年,HTTP2 成为标准。HTTP/1.1 和 HTTP/2 的主要区别是如何在客户端和服务器之间构建和传输数据。HTTP/1.1 依赖于请求 / 响应周期。 HTTP/2 允许服务器 push 数据:它可以发送比客户端请求更多的数据。 这使得它可以优先处理并发送对于首先加载网页至关重要的数据。

Java 9 中有新的方式来处理 HTTP 调用。它提供了一个新的 HTTP 客户端(HttpClient),它将替代仅适用于阻塞模式的 HttpURLConnection (HttpURLConnection 是在 HTTP 1.0 的时代创建的,并使用了协议无关的方法),并提供对 WebSocket 和 HTTP/2 的支持。

其实在 Android 中就已经有了异步调用 API,这些 API 已经被封装在了新的 AndroidSDK 中,现在 Java 终于支持了。此外,HTTP 客户端还提供 API 来处理 HTTP/2 的特性,比如流和服务器推送等功能。全新的 HTTP 客户端 API 可以从 jdk.incubator.httpclient 模块中获取。因为在默认情况下,这个模块是不能根据 classpath 获取的,需要使用 add modules 命令选项配置这个模块,将这个模块添加到 classpath 中。

1
2
3
4
5
6
7
8
9
10
11
12
public class HTTPAPITest {
public static void main(String [] args) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient ();
HttpRequest req = HttpRequest.newBuilder (URI.create ("http://zouchanglin.cn"))
.GET ()
.build ();
HttpResponse<String> response = client.send (req, HttpResponse.BodyHandler.asString ());
System.out.println (response.statusCode ());
System.out.println (response.version ().name ());
System.out.println (response.body ());
}
}

Deprecated 的相关 API

Java 9 废弃或者移除了几个不常用的功能。其中最主要的是 Applet API,现在是标记为废弃的。随着对安全要求的提高,主流浏览器已经取消对 Java 浏览器插件的支持。HTML5 的出现也进一步加速了它的消亡。开发者现在可以使用像 Java Web Start 这样的技术来代替 Applet,它可以实现从浏览器启动应用程序或者安装应用程序。同时,appletviewer 工具也被标记为废弃。

智能 Java 编译工具

官方 Feature:http://openjdk.java.net/jeps/199

智能 Java 编译工具 (sjavac) 的第一个阶段始于 JEP139 这个项目,用于在多核处理器情况下提升 JDK 的编译速度。如今,这个项目已经进入第二阶段,即 JEP199,其目的是改进 Java 编译工具,并取代目前 JDK 编译工具 javac,继而成为 Java 环境默认的通用的智能编译工具。
JDK 9 还更新了 javac 编译器以便能够将 Java9 的代码编译运行在低版本 Java 中。

统一的 JVM 日志系统

官方 Feature:

日志是解决问题的唯一有效途径:曾经很难知道导致 JVM 性能问题和导致 JVM 崩溃的根本原因。不同的 JVM 日志的碎片化和日志选项(例如:JVM 组件对于日志使用的是不同的机制和规则),这使得 JVM 难以进行调试。

解决该问题最佳方法:对所有的 JVM 组件引入一个单一的系统,这些 JVM 组件支持细粒度的和易配置的 JVM 日志

javadoc 的 H5 支持

官方 Feature:

jdk 8 :生成的 java 帮助文档是在 HTML4 中,而 HTML4 已经是很久的标准了。
jdk 9 :javadoc 的输出,现在符合兼容 HTML5 标准。

Javascript 引擎升级:Nashorn

官方 Feature:

Nashorn 项目在 JDK 9 中得到改进(因为 Nashorn 是在 JDK8 中被引入的),它为 Java 提供轻量级的 Javascript 运行时。Nashorn 项目跟随 Netscape 的 Rhino 项目,目的是为了在 Java 中实现一个高性能但轻量级的 Javascript 运行时。Nashorn 项目使得 Java 应用能够嵌入 Javascript。它在 JDK 8 中为 Java 提供一个 Javascript 引擎。

JDK 9 包含一个用来解析 Nashorn 的 ECMAScript 语法树的 API。这个 API 使得 IDE 和服务端框架不需要依赖 Nashorn 项目的内部实现类,就能够分析 ECMAScript 代码。

java 的动态编译器

官方 Feature:

Oracle 一直在努力提高 Java 启动和运行时性能,希望其能够在更广泛的场景达到或接近本地语言的性能。但是,直到今天,谈到 Java,很多 C/C++ 开发者还是会不屑地评价为启动慢,吃内存。简单说,这主要是因为 Java 编译产生的类文件是 Java 虚拟机可以理解的二进制代码,而不是真正的可执行的本地代码,需要 Java 虚拟机进行解释和编译,这带来了额外的开销。

JIT(Just-in-time)编译器可以在运行时将热点编译成本地代码,速度很快。但是 Java 项目现在变得很大很复杂,因此 JIT 编译器需要花费较长时间才能热身完,而且有些 Java 方法还没法编译,性能方面也会下降。AOT 编译就是为了解决这些问题而生的。
在 JDK 9 中, AOT(JEP 295: Ahead-of-Time Compilation)作为实验特性被引入进来,开发者可以利用新的 jaotc 工具将重点代码转换成类似类库一样的文件。虽然仍处于试验阶段,但这个功能使得 Java 应用在被虚拟机启动之前能够先将 Java 类编译为原生代码。此功能旨在改进小型和大型应用程序的启动时间,同时对峰值性能的影响很小。这个 AOT 特性我在之前的文章中也说过:《 HotSpot JVM 类型以及编译模式 》

另外 JVMCI (JEP 243: Java-Level JVM Compiler Interface)等特性,对于整个编程语言的发展,可能都具有非常重要的意义,虽然未必引起了广泛关注。目前 Graal Core API 已经被集成进入 Java 9,虽然还只是初始一小步,但是完全用 Java 语言来实现的可靠的、高性能的动态编译器,似乎不再是遥不可及,这是 Java 虚拟机开发工程师的福音。与此同时,随着 Truffle 框架和 Substrate VM 的发展,已经让个别信心满满的工程师高呼 One VM to Rule Them All!, 也许就在不远的将来 Ploygot 以一种另类的方式成为现实。

对 Java 未来的期望

标准化的 JSON API

一个标准化和轻量级的 JSON API 被许多 java 开发人员所青睐。但是由于资金问题无法在 Java 9 中见到,但并不会削减掉。Java 平台首席架构师 Mark Reinhold 在 JDK 9 邮件列中说:“这个 JEP 将是平台上的一个有用的补充,但是在计划中,它并不像 Oracle 资助的其他功能那么重要,可能会重新考虑 JDK 10 或更高版本中实现。 ” 但是我们目前使用的仍然是阿里的 FastJSON 或者谷歌的 Gson 等 API。

新的货币 API

对许多应用而言货币价值都是一个关键的特性,但 JDK 对此却几乎没有任何支持。严格来讲,现有的 java.util.Currency 类只是代表了当前 ISO 4217 货币的一个数据结构,但并没有关联的值或者自定义货币。JDK 对货币的运算及转换也没有内建的支持,更别说有一个能够代表货币值的标准类型了。

此前,Oracle 公布的 JSR 354 定义了一套新的 Java 货币 API:JavaMoney,计划会在 Java 9 中正式引入。但是目前没有出现在 JDK 9 中。

不过,如果你用的是 Maven 的话,可以做如下的添加,即可使用相关的 API 处理货币。代码参考,可以访问 https://github.com/JavaMoney,里面已经给出了使用说明和示例。

1
2
3
4
5
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>0.9</version>
</dependency>

面临的其他问题

随着云计算和 AI 等技术浪潮,当前的计算模式和场景正在发生翻天覆地的变化,不仅对 Java 的发展速度提出了更高要求,也深刻影响着 Java 技术的发展方向。传统的大型企业或互联网应用,正在被云端、容器化应用、模块化的微服务甚至是函数(FaaS, Function-as-a-Service)所替代。

Java 虽然标榜面向对象编程,却毫不顾忌的加入面向接口编程思想,又扯出匿名对象之概念,每增加一个新的东西,对 Java 的根本所在的面向对象思想的一次冲击。反观 Python,抓住面向对象的本质,又能在函数编程思想方面游刃有余。Java 对标 C/C++,以抛掉内存管理为卖点,却又陷入了 JVM 优化的噩梦。选择比努力更重要,选择 Java 的人更需要对它有更清晰的认识。

Java 需要在新的计算场景下,改进开发效率。这话说的有点笼统,我谈一些自己的体会,Java 代码虽然进行了一些类型推断等改进,更易用的集合 API 等,但仍然给开发者留下了过于刻板、形式主义的印象,这是一个长期的改进方向,但是不得不说 Java 确实还是越变越优秀了。