自Java11起,Oracle JDK将不再免费提供商业用途。
Java11是Java8后的第一个LTS版本,我们对OpenJDK的特性列表做一些 分析。
简介
以下是Java11的特性清单:
- 181: Nest-Based Access Control(基于嵌套的访问控制)
- 309: Dynamic Class-File Constants(动态的类文件常量)
- 315: Improve Aarch64 Intrinsics(优化Aarch64内在函数)
- 318: Epsilon: A No-Op Garbage Collector(一个无操作垃圾收集器)
- 320: Remove the Java EE and CORBA Modules(移除Java EE和CORBA模块)
- 321: HTTP Client (Standard) (HTTP Client API)
- 323: Local-Variable Syntax for Lambda Parameters (lambda参数的局部变量语法)
- 324: Key Agreement with Curve25519 and Curve448
- 327: Unicode 10 (对unicode10的支持)
- 328: Flight Recorder(飞行记录器)
- 329: ChaCha20 and Poly1305 Cryptographic Algorithms
- 330: Launch Single-File Source-Code Programs (运行单文件程序)
- 331: Low-Overhead Heap Profiling
- 332: Transport Layer Security (TLS) 1.3
- 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)
- 335: Deprecate the Nashorn JavaScript Engine (弃用Nashron)
- 336: Deprecate the Pack200 Tools and API
提出问题:
- 那些是日常会用到的?重点是?
代码及完整文件地址:
https://github.com/teaho2015-blog/java11-feature-learning
181: Nest-Based Access Control(基于嵌套的访问控制)
我们先看一个例子:
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();
}
}
该改动要解决的问题:
-
Java语言规范允许在同一个源文件中编写多个类。对于用户的角度来说,在同一个类文件里的class应该共享同样的访问控制体系。 为了达到目的,编译器需要经常需要通过附加的access bridge扩大private成员的访问权限到package。 这种bridge和封装相违背,并且轻微的增加程序的大小,会干扰用户和工具。
-
还有一个问题是反射与源码调用不一致。当使用java.lang.reflect.Method.invoke从 一个nestmate调用另一个nestmate私有方法时会报IllegalAccessError错误。 这个是让人不能理解的,因为反射应该和源码级访问拥有相同权限。
现有情况:
现有的类文件格式定义了 InnerClasses 和 EnclosureMethod 属性(JVMS 4.7.6 和 4.7.7),以允许 Java 源代码编译器(如 javac)具体化源级嵌套关系。
每个嵌套类型都编译为它自己的类文件,不同的类文件通过这些属性的值“链接”。
虽然这些属性足以让 JVM 确定嵌套关系,但它们并不直接适用于访问控制,并且本质上与单个 Java 语言概念相关联。
JVM对嵌套成员的访问控制改动
为了允许更广泛、更通用的嵌套概念,而不是简单的 Java 语言嵌套类型,并且为了有效的访问控制检查,建议修改类文件格式以定义两个新属性。 一个嵌套成员(通常是顶级类)被指定为嵌套主机,并包含一个属性 (NestMembers) 来标识其他静态已知的嵌套成员。 每个其他嵌套成员都有一个属性 (NestHost) 来标识其嵌套主机。
我们调整了JVM访问规则,增加了如下条目(to JVMS 5.4.4):
一个field或method R可以被class或interface D访问,当且仅当如下任一条件为真:
- ……
- R是私有的,并且声明在另一个class或interface C中,并且C和D是nestmates
嵌套成员反射API
正因Java引入了新的类文件属性,那么惯常地Java会提供新的反射机制来检查或查询这些属性。
引入了三个方法java.lang.Class: getNestHost, getNestMembers, and isNestmateOf。
309: Dynamic Class-File Constants(动态的类文件常量)
扩展 Java 类文件格式以支持新的常量池形式 CONSTANT_Dynamic。
Loading a CONSTANT_Dynamic will delegate creation to a bootstrap method, just as linking an invokedynamic call site delegates linkage to a bootstrap method.
invokedynamic的协议设计者(例如 Java 8 中添加的 LambdaMetafactory)经常需要根据现有常量集对行为进行编码, 这反过来又需要在引导程序本身中进行额外的容易出错的验证和提取逻辑。 更丰富、更灵活、更高度类型化的常量消除了invokedynamic协议开发中的挣扎,并促进和简化了编译器逻辑。
CONSTANT_Dynamic还在发展,未来还有一些工作需要做。
315: Improve Aarch64 Intrinsics(优化Aarch64内在函数)
改进现有的字符串和数组内在函数,并在 AArch64 处理器上为 java.lang.Math 包下的 sin,cos 和 log 函数实现新的内在函数。
318: Epsilon: A No-Op Garbage Collector(一个无操作垃圾收集器)
Epsilon是一个不收集垃圾的垃圾收集器,开启参数-XX:+UseEpsilonGC。 他的工作是在已分配内存的单个连续块中实现线性分配来工作。 System.gc()对Epsilon是不起作用的。
应用场景:
- 性能测试
- 内存压力测试
- VM interface测试。
- 寿命极短的工作
- Last-drop latency improvements(最后一滴延迟改进)
- Last-drop throughput improvements(最后一滴吞吐量改进)
320: Remove the Java EE and CORBA Modules(移除Java EE和CORBA模块)
在Java se 9,如下Java EE和CORBA相关模块被标记为deprecated,在Java11如何模块被正式移除
- java.xml.ws (JAX-WS, plus the related technologies SAAJ and Web Services Metadata)
- java.xml.bind (JAXB)
- java.activation (JAF)
- java.xml.ws.annotation (Common Annotations)
- java.corba (CORBA)
- java.transaction (JTA)
移除原因
Java se 6包含了一个完整的Web Service技术栈,为Java开发者提供便利。不过随着发展:
- 这些技术块获得了和Java SE本身并不相关的特性。
- 这些技术由上游java.net维护。由于必须将 OpenJDK 存储库中的 Java SE 版本与上游存储库中的 Java EE 版本同步,这使得维护存在问题。
- 开发者可以从上游Java EE自行获取独立版本并通过Endorsed Standards Override Mechanism 部署它们。
321: HTTP Client (Standard) (HTTP Client API)
该特性在Java9(jEP110)中是处于孵化状态,Java11正式标准化。
该特性支持HTTP/1.1和HTTP/2。
如下是Http client同步、异步、http2调用的简单demo。
/**
* 同步调用 GET
* @param uri
* @throws Exception
*/
public static void syncGet(String uri) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.build();
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
/**
* 异步调用 GET
* @param uri
* @throws Exception
*/
public static void asyncGet(String uri) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.build();
CompletableFuture<HttpResponse<String>> responseCompletableFuture = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
responseCompletableFuture.whenComplete((resp, t) -> {
if (t != null) {
t.printStackTrace();
} else {
System.out.println(resp.body());
System.out.println(resp.statusCode());
}
}).join();
}
/**
* 访问 HTTP2 网址
* @throws Exception
*/
public static void http2() throws Exception {
HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.version(HttpClient.Version.HTTP_2)
.build()
.sendAsync(HttpRequest.newBuilder()
.uri(new URI("https://http2.akamai.com/demo"))
.GET()
.build(),
HttpResponse.BodyHandlers.ofString())
.whenComplete((resp, t) -> {
if (t != null) {
t.printStackTrace();
} else {
System.out.println(resp.body());
System.out.println(resp.statusCode());
}
}).join();
}
323: Local-Variable Syntax for Lambda Parameters (lambda参数的局部变量语法)
这是Java11唯一的语言改动。
这里搭配Java10的新特性JEP 286: Local-Variable Type Inference(局部变量类型推断)一起食用。
请看代码 java11目录->jep323.class 中的demo。
Java11增加了一点,允许在声明lambda表达式时在表达式的参数使用var。
(var x) -> System.out.println(x);
作用是什么呢?
为了统一并为了支持lambda参数使用注解
(@NotNull var x) -> System.out.println(x);
(@Number var x) -> System.out.println(x);
324: Key Agreement with Curve25519 and Curve448
实现RFC 7748 [link]中所述,使用 Curve25519 和 Curve448 实现密钥协议。
这是一个密码学相关(ECDH密钥合意协议)的变更,更改是java.security包。
327: Unicode 10 (对unicode10的支持)
Java11实现了9.0,增加了7500字符和六个脚本(Unicode文本集合),实现了Unicode10因此增加了8518个字符和四个脚本(Unicode文本集合)。
328: Flight Recorder(飞行记录器)
JDK Flight Recorder 是一个用于收集有关正在运行的 Java 应用程序的诊断和分析数据的系统。
它本身对运行期系统的侵入性很小,同时又能提供相对准确和丰富的运行期信息,以极低的性能开销集成到 Java 虚拟机 (JVM) 中,专为分析重负载的生产环境而设计。
在Java11前Flight Recorder和Java mission Control(JMC)都是商业产品,仅在Oracle JDK可用。那时候可以这样开启:
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder MyHelloWorldApp
现在,JFR在OpenJDK 11中是开源的,并且在OpenJDK11/bin文件夹中可用。
指标测量:
- 只有最多1%的性能损耗
- 未启用时没有可衡量的性能开销