JDK 11 特性
做为java开发JDK的更新内容是必须要关注的,这里我把JDK11的相关的JEP(JDK Enhancement Proposals),汇总并偿试了一下。 分享一下相关的改进点。 历史所有JEP:http://openjdk.java.net/jeps/0
JDK11发版 JEP 汇总
JDK11 于2018年9月25日发布正式版,其中官方给出的改进JEP如下:
JEP-181 嵌套类可见性控制 JEP-309 动态类文件常量 JEP-315 改进 Aarch64 Intrinsics JEP-318 Epsilon–一个无操作的垃圾收集器 JEP-320 删除 Java EE 和 CORBA 模块 JEP-321 HttpClient JEP-323 用于 Lambda 参数的局部变量语法 JEP-324 Curve25519 和 Curve448 算法的密钥协议 JEP-327 Unicode 10 JEP-328 Flight Recorder(飞行记录器) JEP-329 haCha20 和 Poly1305 加密算法支持 JEP-330 Launch Single-File Source-Code Programs(启动单一文件的源代码程序) JEP-331 低开销的 Heap Profiling JEP-332 TLS 1.3支持 JEP-333 ZGC: A Scalable Low-Latency Garbage Collector(可伸缩低延迟垃圾收集器) JEP-335 弃用 Nashorn JavaScript 引擎 JEP-336 弃用 Pack200 工具和 API
有些泛及底层有些泛及开发的方方面面,后面对这些特性进行逐说明,以及使用JDK11开发我们需要注意的事项。
JEP-181 嵌套类可见性控制
这一提案是为了增强自Java 1.1即引入的嵌套类设计。 嵌套类主要有两个用处。 第一是因为其只使用于很短的代码块中,在Java8之前,这主要依靠实现一个匿名类来完成。Java8之后,这种用法可以被lambda表达取代。 另一种用法是因为需要访问另一个类的内部。嵌套类具有和成员变量以及成员方法相同的访问权限。 JEP181主要是为了解决JVM级别的权限与源码权限不一致的问题。
代码语言:javascript复制public class JEP181 {
public static class Nest1 {
private int varNest1;
public void f() throws Exception {
final Nest2 nest2 = new Nest2();
//这里没问题
nest2.varNest2 = 2;
final Field f2 = Nest2.class.getDeclaredField("varNest2");
//这里在java8环境下会报错,在java11中是没问题的
f2.setInt(nest2, 2);
System.out.println(nest2.varNest2);
}
}
public static class Nest2 {
private int varNest2;
}
public static void main(String[] args) throws Exception {
new Nest1().f();
}
}
运行结果 java11: 2
Java8:
Exception in thread "main" java.lang.IllegalAccessException: Class JEP181
主要问题出在f2.setInt(nest2,2)
,这里由于在Nest2
中是private的,所以无法直接set值。但是却又可以直接调用nest2.var2=2
来设置该值,因为嵌套类是可以访问别的嵌套类的私有属性的。Java 11修复了这个令人困惑的现象。
JEP-309 动态文件常量
这其实是一个联动一个比较早的改近。Java SE 7 已将 invokedynamic 引入了其指令集。Java 开发人员通常不会注意到此功能,它隐藏在 Java 字节码中。 Java的类型文件格式将被拓展,支持一种新的常量池格式:CONSTANT_Dynamic,加载CONSTANT_Dynamic会将创建委托给bootstrap方法。
目标: 其目标是降低开发新形式的可实现类文件约束带来的成本和干扰。
JEP-315 改进 Aarch64 Intrinsics
优化了现有的字符串和数组内部函数,并在Arm64或Aarch64处理器上为Math.sin() ,**Math.cos()和Match.log()**实现了新的内部函数。这意味着更好的性能。
内部函数用于利用特定于CPU体系结构的汇编代码来提高性能。
JEP-318 Epsilon–一个无操作的垃圾收集器
开发一个处理内存分配但不实现任何实际内存回收机制的 GC。 一旦可用的 Java 堆耗尽,JVM 将关闭。
它为以下内容分配内存:
性能测试。 内存压力测试。 VM 接口测试。 寿命极短的工作。 最后一滴延迟改进。(Last-drop latency improvements.) 最终吞吐量提高。 现在,Elipson 仅适用于测试环境。这将导致生产中的 OutOfMemoryError 并使应用程序崩溃。 Elipson 的好处是没有内存清除开销。因此,它将给出准确的性能测试结果,我们不再可以通过 GC 来停止它。
注意:这是一项实验性功能。
JEP-320 删除 Java EE 和 CORBA 模块
Java 9 中已经弃用了这些模块,现在将它们完全删除。 这个的话,主要还是Spring 的原因。JavaEE 比较重,开发配置特别繁锁,Spring的轻量化是事实的标准,更加简单的使用,导致像 EJB 这种重型框架没有市场,删除是必然的。
下面的包被删除:
java.xml.ws,java.xml.bind,java.activation,java.xml.ws.annotation,java.corba,java.transaction,java.se.ee,jdk.xml.ws,jdk.xml.bind
JEP 321 HttpClient
Java 11 标准化了 Http CLient API。其实就是重写了 HttpClient 内部逻辑 ,接口没变。
目前版本已经支持HTTP1.1、HTTP2、websocket等常用的基于http的协议,并支持了了同步、异步、响应式等交互方式。当前版本的实现还是比较简单,没有对于常用restful、content-type的封装支持。
JEP-323 用于 Lambda 参数的局部变量语法
这个算是一堆 JEP 中唯一在语法特性的改进。 Java 10 中引入了局部变量类型推断 var,示例:
代码语言:javascript复制var list = new ArrayList<String>();
java10中需要显示的声明 var 在 lambda 中的定义
代码语言:javascript复制List<String> list = Arrays.asList("嗯哼", "啊哈", "哦吼");
String result = list.stream()
.map((var x) -> x.toUpperCase())
.collect(Collectors.joining(","));
System.out.println(result2);
JEP 323 允许 var
用于声明隐式类型的 Lambda 表达式的形式参数,Java8 中也是允许在,只是在Java10中删除了这个特性,Java11中又把这个特性拿回来了:
List<String> list = Arrays.asList("嗯哼", "啊哈", "哦吼");
String result = list.stream()
.map(x -> x.toUpperCase())
.collect(Collectors.joining(","));
JEP-324 Curve25519 和 Curve448 算法的密钥协议
密码学相关项目,它将现有的椭圆曲线Diffie-Hellman(ECDH)方案替换为Curve25519和Curve448算法,这是RFC 7748中定义的关键协议方案。
GenerateKeyPairs.java
代码语言:javascript复制package com.mkyong.java11.jep324;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.NamedParameterSpec;
public class GenerateKeyPairs {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
kpg.initialize(paramSpec);
// equivalent to kpg.initialize(255)
// alternatively: kpg = KeyPairGenerator.getInstance("X25519")
KeyPair kp = kpg.generateKeyPair();
System.out.println("--- Public Key ---");
PublicKey publicKey = kp.getPublic();
System.out.println(publicKey.getAlgorithm()); // XDH
System.out.println(publicKey.getFormat()); // X.509
// save this public key
byte[] pubKey = publicKey.getEncoded();
System.out.println("---");
System.out.println("--- Private Key ---");
PrivateKey privateKey = kp.getPrivate();
System.out.println(privateKey.getAlgorithm()); // XDH
System.out.println(privateKey.getFormat()); // PKCS#8
// save this private key
byte[] priKey = privateKey.getEncoded();
}
}
结果:
代码语言:javascript复制--- Public Key ---
XDH
X.509
---
--- Private Key ---
XDH
PKCS#8
[B@42e26948
进一步阅读 有关更多示例,请参考JEP 324和Oracle – Java安全标准算法名称。
JEP-327 Unicode 10
Unicode 10.0增加了8,518个字符,总共136,690个字符。这些增加包括4个新脚本,总共139个脚本,以及56个新表情符号字符。
看看效果:
代码语言:javascript复制public class PrintUnicode {
public static void main(String[] args) {
String codepoint = "U 1F92A";
System.out.println(convertCodePoints(codepoint));
}
// Java, UTF-16
// Convert code point to unicode
static char[] convertCodePoints(String codePoint) {
Integer i = Integer.valueOf(codePoint.substring(2), 16);
char[] chars = Character.toChars(i);
return chars;
}
}
结果: