jdk 10 主要的新特性参考:
openjdk JDK 10
baeldung New Features in Java 10
JDK 10 的新特性
- 286: Local-Variable Type Inference (局部变量类型推断)
- 296: Consolidate the JDK Forest into a Single Repository (JDK库的合并)
- 304: Garbage-Collector Interface (统一的垃圾回收接口)
- 307: Parallel Full GC for G1 (G1并行Full GC)
- 310: Application Class-Data Sharing (应用程序类数据共享)
- 312: Thread-Local Handshakes (ThreadLocal握手交互)
- 313: Remove the Native-Header Generation Tool (javah) (移除JDK中附带的javah工具)
- 314: Additional Unicode Language-Tag Extensions (附加的Unicode语言标记扩展)
- 316: Heap Allocation on Alternative Memory Devices
- 317: Experimental Java-Based JIT Compiler (实验性的基于 Java 的 JIT 编译器)
- 319: Root Certificates (根证书)
- 322: Time-Based Release Versioning (基于时间的发布版本)
下面针对比较重要的特性做说明。
局部变量类型推断(var)
Local Variable Type Inference Style Guidelines
Java 10 LocalVariable Type-Inference
Java 10 采用了一个叫做 var 的保留类型来实现局部变量推断。要特别注意的是,为了兼容旧版本,var 不是关键字,而是一个保留类型,也就意味着你仍然可以像这样用 var 为你的变量和函数命名:
1 | int var = 10; |
请注意,var 的作用仅仅是推断变量类型,变量仍然是静态类型的,与 JS 中的 var 作用完全不同。下面这段代码无法通过编译:
1 | var i = 10; |
var 还能用来声明一些不可指示类型(Non-denotable types)的变量:
1 | var obj = new Object() { // type of 'obj' is A anonymous class types |
var用于声明不可指类型的变量特性的妙用
Java 8 的 lambda 表达式不能够捕获可变变量,也就是说下面这个代码是错误的:
1 | int count = 0; |
之前想要绕过这个限制,我们可以用单元素的数组实现。而在 Java 10 中我们又多了一种选择:
1 | var context = new Object() { |
var 还能够帮助我们实现嵌套函数:
1 | int factorial(int i) { |
语言特性
集合增强
List,Set,Map 提供了静态方法copyOf()返回入参集合的一个不可变拷贝。
1 | static <E> List<E> copyOf(Collection<? extends E> coll) { |
使用 copyOf() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。
并且,java.util.stream.Collectors 中新增了静态方法,用于将流中的元素收集为不可变的集合。
1 | var list = new ArrayList<>(); |
Optional 增强
Optional 新增了orElseThrow()方法来在没有值时抛出指定的异常。
1 | Optional.ofNullable(cache.getIfPresent(key)) |
Garbage-Collector Interface
垃圾收集器接口。
在 hotspot/gc 代码实现方面,引入一个干净的垃圾收集器接口,改进不同垃圾收集器源代码的隔离性。这样添加新的或者删除旧的 GC,都会更容易。
Parallel Full GC for G1
为了降低G1垃圾回收器最坏情况下的延迟,使Full GC的 mark-sweep-compact 算法并行执行。执行的线程可以通过-XX:ParallelGCThreads 设置,同时也受到 Young 和 Mixed 回收器线程的影响。 JEP 307: Parallel Full GC for G1
The G1 garbage collector is the default one since JDK 9. However, the full GC for G1 used a single threaded mark-sweep-compact algorithm.
This has been changed to the parallel mark-sweep-compact algorithm in Java 10 effectively reducing the stop-the-world time during full GC.
Application Class-Data Sharing
Java 之前( JDK 5 )就引入了类数据共享机制,Class data sharing (CDS) ,以减少 Java 程序的启动时间,降低内存占用。简单来说,Java 安装程序会把 rt.jar 中的核心类提前转化成内部表示,转储到一个共享的文件中(shared archive)。多个 Java 进程(或者说 JVM 实例)可以共享这部分数据。之前只允许 bootstrap class loader , jdk 10也允许app class loader 和自定义 classloader共享archived classes。
java-10-performance-improvements
Remove the Native-Header Generation Tool
从 JDK 8 开始,javah 的功能已经集成到了 javac 中。所以,javah 可以删掉了。
Additional Unicode Language-Tag Extensions
Enhance
java.util.Localeand related APIs to implement additional Unicode extensions of BCP 47 language tags.
Experimental Java-Based JIT Compiler
Graal 是一个基于 Java 语言编写的 JIT 编译器,是 JDK 9 中引入的实验性 Ahead-of-Time (AOT) 编译器的基础。
Oracle 的 HotSpot VM 便附带两个用 C++ 实现的 JIT compiler:C1 及 C2。在Java 10 (Linux/x64, macOS/x64) 中,默认情况下HotSpot 仍使用C2,但通过向java 命令添加-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
参数便可将 C2 替换成 Graal。
PS. JIT
JIT(just in time 即时编译器),当虚拟机发现某个方法或代码块运行特别频繁时,就会把这些代码认定为 Hot Spot Code 热点代码,为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化。
即使开启了JIT,也少不了代码编译和字节码解释的过程。JIT处理的是热点代码(hotspot code)。热点代码就是频繁执行的代码块,比如循环里面的代码。JIT有一套逻辑判断是否热点代码。
既然JIT处理后的是机器能够快速执行的代码,为啥还要解释执行呢,干嘛不把全部代码编译成机器代码呢?这是由于编译本地代码比较费时间,而且编译后还要进行进一步的优化导致耗时更久;而解释器是能够立即解释字节码文件的,毕竟我们的应用放到服务器上的时候就已经是字节码文件了,解释器可以拿来直接用。而且解释器执行的时候占用的内存更小,在内存受限的场景难以使用编译器(比如手机上)。编译器会概率性地选择多数时候都能提升运行效率的手段进行优化,如果“优化”后发现还不如不优化(甚至执行有问题)就得“逆优化”,回退到解释执行状态。
我们可以通过最简单的查看Java版本的命令查看Java是否使用了编译器:
1 | > java -version |
最后输出的mixed mode代表是混合模式,也就是先解释执行,并逐步将热点代码代替为机器代码。不使用编译器的模式叫interpreted mode;优先使用编译器的模式叫compiled mode,compiled mode会优先采用编译方式执行程序,如果编译执行有问题就回退到解释执行。
Root Certificates
在 JDK 中提供一组默认的根证书。
Open-source the root certificates in Oracle’s Java SE Root CA program in order to make OpenJDK builds more attractive to developers, and to reduce the differences between those builds and Oracle JDK builds.
Time-Based Release Versioning
基于时间的版本字符串。修改 Java SE 平台和 JDK 版本字符串机制。
- A new Java release every six months. The March 2018 release is JDK 10, the September 2018 release is JDK 11, and so forth. These are called feature releases and are expected to contain at least one or two significant features
- Support for the feature release will last only for six months, i.e., until next feature release
- Long-term support release will be marked as LTS. Support for such release will be for three years
- Java 11 will be an LTS release
java -version will now contain the GA date, making it easier to identify how old the release is:
1 | $ java -version |