即将到来的Java 12版本!

发表时间: 2019-01-14 15:29

近几个月,Java SE 即将收费的消息引发开发者内心的不安,不少人纷纷表示是时候弃 Java 而转战 Kotlin 战场,同时也有部分程序员仍静观其变。不过根据最新的消息,Java 12 即将于今年的 3 月 19 号到来,而此次也将是 Oracle 正式对 JDK 8/11 用户协议变更后首个发布的版本,对此,我们是否还有必要跟进升级?而身处收费漩涡的开发者又该何去何从?

每半年更新一次的 Java 已让不少开发者望尘莫及,但 Oracle 似乎并未完全意识到这一点。就在去年 9 月 Java 11 正式发布之后,有关 JDK 12 的消息就接踵而至,且至今就未曾断过。不仅如此,如今连 JDK 12 正式版还未到来之际,JDK 13 的早期构建版本就发布了(http://jdk.java.net/13/),不知广大的 Java 工程师会作何感想。

回看 Java 12,它已于去年 12 月正式进入 Rampdown Phase One 阶段,这意味着该版本所有新的功能特性被冻结,不会再加入更多的 JEP 。Rampdown Phase One 阶段将持续一个月,主要修复 P1-P3 级错误。根据 JDK 官网日程来看,JDK 12 的候选发布版本将定于 2 月初发布,GA 版本将于 3 月中旬发布。

接下来,我们将共同探讨 Java 12 中有哪些新的特性?

JDK 12 的主要特性

作为“功能性版本”,JDK 12 总共包含 8 个新的 JEP 。

  • JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)

可由 RedHat 支持 aarch64 和 amd64。这里所述的 Shenandoah 垃圾回收器,可通过在 Java 线程运行的同时进行疏散 (evacuation) 工作来减少停顿时间。使用 Shenandoah 的暂停时间与堆大小无关,这意味着无论堆是 200MB 还是 200GB ,都具有相同的暂停时长。

它将作为实验性功能提供,因此为了使用它,“-XX:+
UnlockExperimentalVMOptions” 需要和 “-XX:+ UseShenandoahGC”命令行一起使用。

此外,默认(Oracle 的)OpenJDK 版本不包含此功能。开发者们可以使用其他早期版本或自己构建。

在 Oracle 的 OpenJDK 早期发布版本中:

$ java -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGCError occurred during initialization of VMOption -XX:+UseShenandoahGC not supported

或者参考以下链接自己构建:
https://metebalci.com/blog/custom-openjdk-12-builds-on-ubuntu-18-04/

  • JEP 230: Microbenchmark Suite

这是一套微基准测试,使开发者能够基于现有的 Java Microbenchmark Harness(JMH)轻松测试 JDK 的性能,并添加到 JDK 源代码中。

示例如下,但值得注意的是,以下的步骤需要开发者具备一个能够从源代码构建 JDK 的系统:

$ cd jdk-src$ sh make/devkit/createJMHBundle.sh$ ./configure --with-jmh=build/jmh/jars --enable-headless-only$ make test TEST="micro:java.lang.reflect"... after many lines of output ...Test selection 'micro:java.lang.reflect', will run:* micro:java.lang.reflectRunning test 'micro:java.lang.reflect'# JMH version: 1.21# VM version: JDK 12-internal, OpenJDK 64-Bit Server VM, 12-internal+0-adhoc.ubuntu.jdk-src# VM invoker: /home/ubuntu/jdk-src/build/linux-x86_64-server-release/images/jdk/bin/java# VM options: --add-opens=java.base/java.io=ALL-UNNAMED# Warmup: 5 iterations, 10 s each# Measurement: 5 iterations, 10 s each# Timeout: 10 min per iteration# Threads: 1 thread, will synchronize iterations# Benchmark mode: Average time, time/op# Benchmark: org.openjdk.bench.java.lang.reflect.Clazz.getConstructor# Run progress: 0.00% complete, ETA 01:31:40# Fork: 1 of 5# Warmup Iteration 1: 19.849 ns/op# Warmup Iteration 2: 19.067 ns/op# Warmup Iteration 3: 20.044 ns/op# Warmup Iteration 4: 20.050 ns/op# Warmup Iteration 5: 20.061 ns/opIteration 1: 20.037 ns/opIteration 2: 20.019 ns/opIteration 3: 20.070 ns/opIteration 4: 20.052 ns/opIteration 5: 20.024 ns/op.. and continues running many more tests
  • JEP 325: Switch Expressions (Preview)

该 JEP 中,switch 语句主要有两个改变:

  • 引入了 -> 语法且无须 break 语句;
  • switch 可以作为表达式,因此它可以有一个值,或者它可以返回一个值。

示例:

public class JEP325 { public static void main(String[] args) { // args[0] is the day of week, starting from 1-sunday final int day = Integer.valueOf(args[0]); // traditional switch switch (day) { case 2:  case 3:  case 4:  case 5:  case 6:  System.out.println("weekday"); break; case 7: case 1: System.out.println("weekend"); break; default: System.out.println("invalid"); } // case L -> syntax // no break necessary, only code next to -> runs switch (day) { case 2, 3, 4, 5, 6 -> System.out.println("weekday"); case 7, 1 -> System.out.println("weekend"); default -> System.out.println("invalid"); } // switch expression // then switch should be exhaustive if used as expression // break <value_of_switch_expression> syntax for blocks final String attr = switch (day) { case 2, 3, 4, 5, 6 -> "weekday"; case 7, 1 -> "weekend"; // it is possible to do this without a block and break // so default -> "invalid"; is actually enough here default -> { break "invalid"; } }; System.out.println(attr); }}

根据 arg [0],它输出相同的字符串(weekend、weekday 或 invalid)三次。

  • JEP 334: JVM Constants API

JEP 334 提出了一个 API 建模关键类文件和运行时工件,如常量池。 这样的 API 将包含类似 ConstantDesc、ClassDesc 的类,此 API 的草案可在参考:

https://cr.openjdk.java.net/~vromero/constant.api/javadoc.04/java/lang/invoke/constant/package-summary.html

这对于操作类和方法的工具很有用。

  • JEP 340: One AArch64 Port, Not Two

在 ARM 64 位中有两组不同的资源,即端口。 一个由 Oracle 提供,arm64(hotspot / cpu / arm),另一个是 aarch64(hotspot / cpu / aarch64)。

此 JEP 删除了 arm64,因此将删除与 hotspot / cpu / arm 下的 #ifdefs 一起使用的所有源代码,并且 64 位 ARM 构建将默认为 aarch64。 hotspot / cpu / arm 仍将提供 32 位 ARM 端口。

$ cd jdk-src/src/hotspot/cpu/arm$ hg update jdk-12+1$ grep -r AARCH64 * | wc -l1694$ hg update jdk-12+21$ grep -r AARCH64 * | wc -l0
  • JEP 341: Default CDS Archives

类数据共享(CDS)是一种减少启动时间和从内存共享中受益的功能。但是,如果未使用安装程序安装 JRE,则默认情况下不会生成 CDS 存档,并且必须手动运行 java -Xshare:dump。

这可以在 JDK 11 中观察到。如果从 http://jdk.java.net/11/ 安装 JDK 11 GA Release,则 lib / server 文件夹不包含 CDS 存档 classes.jsa 文件。 如果你运行 java -Xshare:dump,它将被生成。

使用此 JEP,默认情况下将生成 CDS 存档。

  • JEP 344:Abortable Mixed Collections for G1

为了满足用户提供的暂停时间目标,此 JEP 使 G1 垃圾回收器中止垃圾收集过程,方法是将要设置的垃圾收集区域(mixed collection set)拆分为强制和可选部分,并中止垃圾收集。如果没有达到暂停时间目标,则为可选部分。

  • JEP 346:Promptly Return Unused Committed Memory from G1

此 JEP 使 G1 垃圾回收器在一段低应用程序活动后将垃圾收集的内存区域返回给操作系统。目前 G1 只是在完全 GC(或并发周期)之后才将内存返回到操作系统,因此实际上它可能根本没有将垃圾收集的内存返回给操作系统。

被删除的功能——原始字符串字面量

在即将发布的 JDK 12 中,原有提案之一的原始字符串字面量(raw string literals)于一个月前被 JDK 开发团队从该版本中剔除了,这让不少满怀期待的开发者难免有些失落。

根据该提案官方描述显示,原始字符串字面量可以跨多行源代码,并且里面的转义串不会被解析,例如\ n,或者像\ uXXXX 形式的 Unicode 转义。它的存在可以让开发者更容易以可读形式表达字符序列,也可以提供针对除 Java 之外的语法字符串等等。

而 Oracle 究竟是为何会延迟原始字符串字面量在 JDK 12 中的呈现。对此,Oracle Java 语言架构师 Brian Goetz 在邮件中解释道:

我们认为基于当前的状态提供预览会对 Java 语言不利。同时,我们也感到失望,因为这意味着这个特性需要更长一点时间才能变成 Java 语言的一部分,但我们认为这是最佳选择。

虽然我们可以预料到,任何语言特性都会收到大量诸如“我更希望它不是这样的”的反馈,在我们审查收到的反馈时,我不再确信我们在复杂性和表现力之间作出了正确的权衡,或者我们已经探索到了足够的设计方案,以确保当前的方案是我们能做出的最优方案。通过移除这个特性,我们可以继续完善设计,探索更多选项,以便可以提供一个能满足预览特性流程(Preview Feature process,JEP 12)要求的预览。

Java 工程师已经如此艰难,是否还要跟着更新跑?

Java 如此的更新速度已经让不少开发者吃不消了,且 Oracle 对如今长期版本 JDK 8、JDK 11 的开发者使用守则也进行了变更:

  • 去年四月,Oracle 宣布自 2019 年 1 月起,Java SE 8 公开更新将不向没有商用许可证的业务、商用或生产用途提供。即未来开发者还想使用 JDK 8,Oracle 将不会提供免费的技术支持,需要另外收费。
  • 十月,Oracle 修改了 JDK 11 中的用户协议。即新版 Oracle JDK 不可以用在数据处理、商业、产品、或者内部商业用途(需要购买 License),仅可免费用于开发、测试、原型、演示。

整体而言,JDK 用户协议的修改或许对于个人开发者而言影响不大,毕竟除了收费的 Oracle JDK,大家还有一个 OpenJDK 以及其他免费的 JDK 可供选择。但是对于 Java 商用项目的企业而言,则相对较为麻烦了。来自 CSDN 博客专家@资深架构师 曾

分析道

:Oracle 的收费并没有区分客户和合作伙伴,专家们建议下载 Java SE 时一定要谨慎,已经下载的用户在 LMS 打电话过来之前一定要对使用情况进行审查,做好充分的准备。但是目前并没有办法将需要付费的 Java SE 产品和免费的 Java SE 产品分开,Oracle 也没有提供独立的免费 Java SE 安装软件,所以无论用户是否需要,从 Oracle 官方下载的 Java SE 都将包含所有内容,也即免费和收费的内容都有,因此也必须根据 Oracle 的要求进行付费。为此有合规专家建议用户“对自己的 Java SE 使用方式进行审计,确保只安装有权使用的那部分,同时删除没使用的内容”。

此外,不仅如今的开发工具限制多多,Java 人才市场也逐渐趋于饱和。根据招聘机构 100offer 最新发布的《2018 年 Java 人才市场报告》显示,过往的一年中 Java 语言虽依旧稳居各大编程语言排行榜前列,但是 2018 年 Java 求职市场整体求职难度变大,且全年波动更剧烈,淡旺季区别明显,呈现出一种「僧多粥少」的局面。

那么在如此的局面的之下,开发者到底是否值得升级到最新版本?是否升级就意味着更上了技术潮流而不被淘汰?

其实不然,单从版本的属性来看,Java 8 和 Java 11 作为长期支持版本(LTS),且据 Oracle 此前的声明透露,Java 11 之后的主要版本为 Java 17,这意味着 Java 12-16 均为小版本更新。相比长期支持版本通常会获得 Oracle 四年或更长时间的技术支持和安全补丁,这些小版本无论是从安全性还是稳定性上,均不值得开发者丢弃 JDK 8/11 而升级到 12。

此外,来自国外的知名的 Java 博主 Stephen Colebourne 也曾发文建议道,作为开发者的你,如果真的准备升级到 Java 12,必须考虑好每六个月更新一次的 Java 所带起来的依赖反应:

  • 开发资源:你的团队可能会非常忙碌或规模太小,你是否能保证两年后从 Java 15 升级到 16 的开发时间吗?
  • 构建工具和 IDE:你使用的 IDE 是否会在发布当天支持每个新版本?Maven? Gradle 呢? 如果不是,你是否有后备计划吗?请记住,你只有1个月的时间来完成升级、测试并将其发布到生产环境中。此外还包括 Checkstyle,JaCoCo,PMD,SpotBugs 等等其他工具。
  • 依赖关系:你的依赖关系是否都准备好用于每个新版本?请记住,它不仅仅是直接依赖项,而是技术堆栈中的所有内容。字节码操作库尤其受到影响,例如 ByteBuddy 和 ASM。
  • 框架:这是另一种依赖,但是一个大而重要的依赖。在一个月的狭窄时间窗口内,Spring 会每六个月发布一个新版本吗?Jakarta EE(以前的 Java EE)会吗?如果它们不这样做会怎么样?

对此,你会升级用最新版本的 Java 吗?当前你正在使用哪个版本的 JDK 呢?欢迎下方留言,分享你的观点。

参考:

https://metebalci.com/blog/what-is-new-in-java-12/#introduction

https://mail.openjdk.java.net/pipermail/jdk-dev/2018-December/002402.htm