入职新公司两个月了,用 JDK11 写了两个月 JDK8 的代码,再也憋不住想看看 JDK11 的新特性了。没用过 JDK9,10 . 那就说说 JDK8-JDK11 的变化吧。

#

  • 语法增强
    • 本地变量类型推断
    • Collection 增强
    • Stream 增强
    • Optional 增强
    • InputStream 增强
    • String 增强
  • 模块化开发
  • 新工具
    • REPL 交互式编程
    • Low-Overhead Heap Profiling
    • Flight Recorder
  • 新功能
    • 源代码直接执行
    • 完全支持 Linux 容器
    • 支持 Unicode 10
    • 新支持的加密算法
    • HttpClient
  • 垃圾回收器
    • ZGC
    • Epsilon
    • 更好的 G1
  • 移除与不再推荐使用的类库或功能
    • 移除了 Java EECORBA Moudles
    • Nashorn Javascript 标记为不推荐
    • Pack200 Tools and API 标记为不推荐

# JDK8-JDK11 的语法新特性

# 本地变量类型推断

since JDK10

Java10 以后可以用 var 定义一个局部变量,不用显式写出它的类型。但要注意,被 var 定义的变量仍然是静态类型,编译器会试图去推断其类型。所以,我们需要注意 1 . 不兼容的类型是不能重新赋值的! 2 . 只要编译器无法推断出变量类型,就会编译错误!

举个栗子:

# 基本使用

1
2
3
4
5
public static void test1() {
var str1 = "local variable type interface";
String str2 = "local variable type interface";
System.out.println(str1 == str2); //true
}

# 简化泛型声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 简化泛型声明
*/
public static void test2() {
var lists = new ArrayList<Map<String, List<String>>>();

for (var item : lists) {
var entries = item.entrySet();
for (var entry : entries) {
String key = entry.getKey();
var values = entry.getValue();
for (var value : values) {
System.out.println(value);
}
}
}
}

幸好编译器会有类型提示。如下图。

# 简化 lambda 参数

1
2
3
4
5
6
7
8
9
10
11
12
/**
* lambda参数
* 从Java 11开始,lambda参数也允许使用var关键字:
*/
public static void test3() {
Predicate<String> predNotNull = (var a) -> a != null && !a.isBlank();

String strAfterFilter = Stream.of("I", "", "love", " ", "my", "wife", null, "very", "much")
.filter(predNotNull)
.collect(Collectors.joining(" "));
System.out.println(strAfterFilter); //I love my wife very much
}

# 不兼容的类型赋值

这种直接编译失败,第一行和第二行已经推断出来了 strString 类型。 第三行就不能赋值为 double 类型了。

# 不能推测的类型

但是,对于用习惯了 IDEA 快捷指令的我来说,这个 var 变量,对我来说毫无意义。感觉 jdk 是在炫技,但我毫无兴趣。

比如,在 idea 中,你输入 new ArrayList().var , 然后回车, IDEA 就会为你自动生成类型。
类似的还有 lists.for , lists.fori 等等。所以,个人并不推荐大家使用该语法,并非不能用,比如在 lambda 中使用替换类型时还是比较好的。如果你还没有掌握 xx.var 这种异能加持的话,想用就用吧。

总之,看别人写了个 var 时,不要发出 “哇藕, Java 还可以这么写”。

# Collection 增强

这个比较简单,就是 List , Set , Map 这三种集合多了两个方法 ofcopyOf .

since jdk9

这里直接用三个栗子分别演示一下

# List

List.of 内部是创建一个的 immutable collections 。不可变集合。所以不可以增删改元素。

List.of()List.copyOf() 都是创建的不可变集合

1
2
3
4
5
6
7
8
9
/**
* 演示 List
*/
public static void test1() {
List<Integer> integers = List.of(1, 2, 3, 4);
List<Integer> integers1 = List.copyOf(integers);
System.out.println(integers == integers1); // true
integers.add(5); // UnsupportedOperationException
}

# Set

SetList 的用法类似。 同样的,也是不可变集合。需要注意的是, copyOf 方法,如果形参是可变集合,则返回的也是可变集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 演示 Set
*/
public static void test2() {
Set<Integer> integers = Set.of(1, 2, 3, 4);
Set<Integer> integers1 = Set.copyOf(integers);
System.out.println(integers == integers1); // true
// integers.add(5); // UnsupportedOperationException

Set<Integer> integers2 = new HashSet<>();
integers2.add(1);
integers2.add(2);
integers2.add(3);
Set<Integer> integers3 = Set.copyOf(integers2);
System.out.println(integers3 == integers2); // false

// 元素不能重复 => java.lang.IllegalArgumentException
Set<Integer> integers4 = Set.of(1, 2, 3, 4,3);
}

# Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 演示Map
*/
public static void test3(){
// 使用of创建Map
Map<String, Integer> map1 = Map.of("k1", 2, "k2", 2);
Map<String, Integer> map2 = Map.copyOf(map1);
System.out.println(map1 == map2); // true

// copyOf,取决于传入的map是否为可变集合
HashMap<String, Integer> map3 = new HashMap<>();
map3.put("k1",1);
map3.put("k2",2);
Map<String, Integer> map4 = Map.copyOf(map3);
System.out.println(map3 == map4); //false

// key不能重复 => java.lang.IllegalArgumentExceptio
Map<String, Integer> map5 = Map.of("k1", 2, "k2", 2, "k1", 3);
}

# Stream 增强

since JDK9

Stream 相关内容,新增了 4 个方法.

# 增加单个参数构造方法

1
2
3
4
5
6
7
/**
* 新增单个元素的Stream构造,允许为空
*/
public static void demo1() {
System.out.println(Stream.ofNullable(null).count()); // 0
System.out.println(Stream.of(1).count()); //1
}

# 增加 takeWhile 方法

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 演示take while方法
* <p>
* 从头开始计算,遇到不满足Predicate的元素即停止。
*/
public static void demo2() {
List<Integer> collect1 = Stream.of(1, 2, 3, 4, 5, 3, 2, 1).takeWhile(i -> i <= 3).collect(Collectors.toList());
System.out.println(collect1); // [1, 2, 3]

List<Integer> collect2 = Stream.of(1, 2, 3, 4, 5, 4, 3, 2, 1).takeWhile(i -> i > 6).collect(Collectors.toList());
System.out.println(collect2); // [ ]
}

# 增加 dropWhile 方法

1
2
3
4
5
6
7
8
9
10
11
/**
* 演示 dropWhile 方法
* 从头开始计算,遇到第一个不满足 Predicte的元素时,开始计算。
*/
public static void demo3() {
List<Integer> collect1 = Stream.of(1, 2, 3, 4, 5, 4, 3, 2, 1).dropWhile(i -> i <= 3).collect(Collectors.toList());
System.out.println(collect1); // [1, 2, 3, 4, 5, 4, 3, 2, 1]

List<Integer> collect2 = Stream.of(1, 2, 3, 4, 5, 4, 3, 2, 1).dropWhile(i -> i > 3).collect(Collectors.toList());
System.out.println(collect2); // [4, 5, 4, 3, 2, 1]
}

# iterate 重载方法

这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件) 来指定什么时候结束迭代。

需要注意的是:相比 JDK8 的方法, iterator 是第三个参数,第二个参数是 PredictionPrediction 中进行判断的取值是迭代之后的数值。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 演示 iterate 的重载方法
*/
public static void demo4() {
// Jdk8支持使用这种方式, 生成从1开始的平方数
List<Integer> collect1 = Stream.iterate(1, i -> i * 2).limit(5).collect(Collectors.toList());
System.out.println(collect1); // [1, 2, 4, 8, 16]

// JDK9 支持,加入一个 Prediction, 判断如何终止。
List<Integer> collect2 = Stream.iterate(1, i -> i <= 16, i -> i * 2).limit(10).collect(Collectors.toList());
System.out.println(collect2); // [1, 2, 4, 8, 16]
}

# Optional 增强

Since JDK 9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 提供一个默认的Optional对象
*/
private static void demo1() {
// 定义一个变量, 可能为空 or not
var variable = "jdk 11";

// jdk 8 支持of(),ofNullable() 转换为Optional对象。
List<String> collect = Optional.of(variable).stream().collect(Collectors.toList());

// JDK 8 可以通过 orElse, 当 variable 为空的时候,返回一个默认的字符串值。
Optional.ofNullable(variable).orElse("");

// jdk 9 提供了提供 or() 返回一个默认Optional对象。
Optional.empty().or(() -> Optional.of("jdk 11")).get();
}

# InputStream 加强

InputStream 终于有了一个非常有用的方法: transferTo ,可以用来将数据直接传输到 OutputStream ,这是在处理原始数据流时非常常见的一种用法。

还是举个栗子吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 直接将数据写入输出流
*/
public static void demo1() throws IOException {
var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("readFile.txt");
var javastack = File.createTempFile("writeFile", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
inputStream.transferTo(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}

# String 增强

# isBlank

判断目标字符串是否是空白字符。

使用功能上的问题,感觉还是例子来的舒服。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 判断字符串是否为空
*/
private static void demo1() {
// 半角空格 ===> true
System.out.println(" ".isBlank());

// 全角空格 ===> true
System.out.println(" ".isBlank());

// 半角空格的unicode字符值 ===> true
System.out.println("\u0020".isBlank());

// 全角空格的unicode字符值 ===> true
System.out.println("\u3000".isBlank());

// 制表符 ===> true
System.out.println("\t".isBlank());

// 回车 ===> true
System.out.println("\r".isBlank());

// 换行 ===> true
System.out.println("\n".isBlank());

// 各种空白字符拼接 ===> true
System.out.println(" \t\r\n ".isBlank());
}

# strip,stripLeading 与 stripTrailing

去除字符串的前后字符串

1
2
3
4
5
6
7
8
9
// 全角空格 + 制表符 + 回车 + 换行 + 半角空格 + <内容> + 全角空格 + 制表符 + 回车 + 换行 + 半角空格
var strTest = " \t\r\n 你好 jdk11 \t\r\n ";

// strip 去除两边空白字符
System.out.println("[" + strTest.strip() + "]");
// stripLeading 去除开头的空白字符
System.out.println("[" + strTest.stripLeading() + "]");
// stripTrailing 去除结尾的空白字符
System.out.println("[" + strTest.stripTrailing() + "]");

# repeat

1
2
3
4
5
6
7
var strOri = "jdk11";
var str1 = strOri.repeat(1);
var str2 = strOri.repeat(3);
System.out.println(str1);
System.out.println(str2);
// repeat传入参数为1时,不会创建一个新的String对象,而是直接返回原来的String对象。
System.out.println(str1 == strOri);

# lines

1
2
3
4
5
6
7
8
9
 /**
* 按照换行符拆分字符串
*/
private static void demo3() {
var strContent = "hello java\rhello jdk11\nhello world\r\nhello everyone";
// lines方法用 \r 或 \n 或 \r\n 对字符串切割并返回stream对象
strContent.lines().forEach(System.out::println);
System.out.println(strContent.lines().count());
}

# 模块化开发

Java9 引入了模块化, Java Platform Module Systemjava 平台模块系统,简称 JPMS

这里和大家一起做一下。

# 新建两个 module

我们新建两个模块 core 和 business。 如下图

# core 模块配置

  • 新建一个类 RestResult ,表示公共调用的类。
1
2
3
4
5
6
7
8
9
10
11
12
public class RestResult<T> {

private T data;

private Integer code;

private String errMsg;

public RestResult(T data) {
this.data = data;
}
}
  • 新建一个 module-info.java . 声明 module 信息. exportscom.fxb.learn.module.core 这个包下的类都 export 出去。
    • 如果是一个 java 的普通应用,则在 src 目录下,新建 module-info.java 文件即可。
    • 如果是一个 maven 应用,则需要在 src/main/java 目录下,新建 module-info.java 文件。
1
2
3
4
5
// core 是module的名称
module core {
// 将指定的包下类,export出去
exports com.fxb.learn.module.core;
}

# business 模块配置

  • business 模块下,新建一个 module-info.java . 文件位置上 core 模块中的一致。
1
2
3
module business {
requires core;
}
  • Idea 中配置, business 模块引用 core 模块。

# 写个例子看看

1
2
3
4
5
6
 /**
* 演示模块调用。
*/
private RestResult<User> getUserById() {
return new RestResult<>(new User(1, "fangjiaxiaobai"));
}

# 新工具

JDK 还提供了一些新的工具, REPL 交互式编程, Low-Overhead Heap Profiling (免费的低耗能飞行记录仪和堆分析仪), Flight Recorder (黑盒子)

# REPL 交互式编程

你是否使用 j upter , java 也有了!

Java 提供了一个新的工具 jshellJava 终于可以像 pythonscala 等语言那样,交互式演示语法了

具体命令可以使用 /help 命令查看。

# Low-Overhead Heap Profiling

免费的低耗能飞行记录仪和堆分析仪。

通过 JVMTISampledObjectAlloc 回调提供了一个开销低的 heap 分析方式提供一个低开销的,为了排错 java 应用问题,以及 JVM 问题的数据收集框架。
具有一下功能:

  • 提供用于生产和消费数据作为事件的 API
  • 提供缓存机制和二进制数据格式
  • 允许事件配置和事件过滤
  • 提供 OS , JVMJDK 库的事件

# Flight Recorder

Flight Recorder 源自飞机的黑盒子。 Flight Recorder 以前是商业版的特性,在 java11 当中开源出来,它可以导出事件到文件中,之后可以用 Java Mission Control 来分析。

两种启动方式:

可以在应用启动时配置 java -XX:StartFlightRecording
应用启动之后,使用 jcmd 来录制,如下代码:

1
2
3
$ jcmd <pid> JFR.start  # 启动记录仪
$ jcmd <pid> JFR.dump.filename=recording.jfr # 将记录内容保存到文件里
$ jcmd <pid> JFR.stop # 停止记录仪

不过在 jdk11 是没办法查看 jfr 的。如果想看,安装 jdk12 吧。 不,可以试试 jdk16 , jdk16 也是 LTS 版本!・

JFR 是一套集成进入 JDK、JVM 内部的事件机制框架,通过良好架构和设计的框架,硬件层面的极致优化,生产环境的广泛验证,它可以做到极致的可靠和低开销。在 SPECjbb2015 等基准测试中,JFR 的性能开销最大不超过 1%,所以,工程师可以基本没有心理负担地在大规模分布式的生产系统使用,这意味着,我们既可以随时主动开启 JFR 进行特定诊断,也可以让系统长期运行 JFR, 用以在复杂环境中进行 "After-the-fact" 分析。还需要苦恼重现随机问题吗?JFR 让问题简化了很多
在保证低开销的基础上,JFR 提供的能力也令人眼前一亮,例如:我们无需 BCI 就可以进行 Object Allocation Profiling, 终于不用担心 BTrace 之类把进程搞挂了。对锁竞争、阻塞、延迟,JVM GC、SafePoint 等领域,进行非常细粒度分析。甚至深入 JIT Compiler 内部,全面把握热点方法、内联、逆优化等等。JFR 提供了标准的 Java,C++ 等扩展 API, 可以与各种层面的应用进行定制、集成,为复杂的企业应用栈或者复杂的分布式应用,提供 All-in-One 解决方案。而这一切都是内建在 JDK 和 JVM 内部的,并不需要额外的依赖,开箱即用。

# 新功能

# HttpClient

JDK 9 开始引入 HttpClient API 来处理 HTTP 请求。 从 JDK 11 开始,这个・正式进入标准库包。
参考网址:http://openjdk.java.net/groups/net/httpclient/intro.html

HttpClient 具有以下特性:

  • 支持 HTTP1.1HTTP2 , websocket 协议
  • 支持同步和异步编程模型
  • 将请求和响应主体作为响应式流 ( reactive-streams ) 处理,并使用构建器模式
  • 要发送 http 请求,首先要使用其构建器创建一个 HttpClient 。这个构建器能够配置每个客户端的状态:
    • 首选协议版本 ( HTTP/1.1HTTP/2 )
    • 是否跟随重定向
    • 代理
    • 身份验证

一旦构建完成,就可以使用 HttpClient 发送多个请求。

# HttpRequest

HttpRequest 是由它的构建器创建的。请求的构建器可用于设置:

  • 请求 URI
  • 请求 Method ( GET , PUT , POST )
  • 请求主体 (如果有)
  • 超时时间
  • 请求头

HttpRequest 构建之后是不可变的,但可以发送多次。

# Synchronous or Asynchronous

请求既可以同步发送,也可以异步发送。当然同步的 API 会导致线程阻塞直到 HttpResponse 可用。异步 API 立即返回一个 CompletableFuture ,当 HttpResponse 可用时,它将获取 HttpResponse 并执行后续处理。

# Data as reactive-streams

请求和响应的主体作为响应式流 (具有非阻塞背压的异步数据流) 供外部使用。 HttpClient 实际上是请求正文的订阅者和响应正文字节的发布者。 BodyHandler 接口允许在接收实际响应体之前检查响应代码和报头,并负责创建响应 BodySubscriber

HttpRequestHttpResponse 类型提供了许多便利的工厂方法,用于创建请求发布者和响应订阅者,以处理常见的主体类型,如文件、字符串和字节。这些便利的实现要么累积数据,直到可以创建更高级别的 Java 类型(如 String ),要么就文件流传输数据。 BodySubscriberBodyPublisher 接口可以实现为自定义反应流处理数据。

HttpRequestHttpResponse 还提供了转换器,用于将 java.util.concurrent.FlowPublisher/Subscriber 类型转换为 HTTP ClientBodyPublisher/BodySubscriber 类型。

# 请求协议 HTTP/2

Java HTTP Client 支持 HTTP/1.1HTTP/2 。默认情况下,客户端将使用 HTTP/2 发送请求。发送到尚不支持 HTTP/2 的服务器的请求将自动降级为 HTTP/1.1

以下是 HTTP/2 带来的主要改进:

  • 标头压缩。 HTTP/2 使用 HPACK 压缩,从而减少了开销。
  • 与服务器的单一连接减少了建立多个 TCP 连接所需的往返次数。
  • 多路复用。 在同一连接上,同时允许多个请求。
  • 服务器推送。 可以将其他将来需要的资源发送给客户端。
  • 二进制格式。 更紧凑。

由于 HTTP/2 是默认的首选协议,并且在需要的地方无缝地实现回退到 HTTP/1.1 ,那么当 HTTP/2 被更广泛地部署时, Java HTTP 客户端就无需修正它的应用代码。

具体的 Java Doc 可以参考: https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/package-summary.html

看了 Java Doc , 感觉使用起来比较简单。这里就不举例了。感兴趣的朋友,可以自行深入研究一下。

# 源代码直接执行

一个单文件源代码,也就是说,单独的 java 文件,有 main 方法,且只依赖 jdk 类库以及自己文件内部定义的类,可以直接用 java 执行而无需先编译再执行编译后的 class 文件了。

你可能问了,有什么用呢?我平时也不关系它是否生成了 class 文件。

如果你是做数据相关的工作,可能需要写一些脚本的时候,这却是轻松了很多。

1
2
3
4
5
6
7
8
9
10
➜  learn git:(master) ✗ ll
total 8
-rw-r--r-- 1 wangxiyue staff 411B Nov 9 22:58 SourceCodeExecDemo.java
➜ learn git:(master) ✗ java SourceCodeExecDemo.java
1.解析数据格式.....
2.处理数据.....
3.重组数据.....
➜ learn git:(master) ✗ ll
total 8
-rw-r--r-- 1 wangxiyue staff 411B Nov 9 22:58 SourceCodeExecDemo.java

可以看到确实没有 class 文件生成。

# 完全支持 Linux 容器

Docker 容器中运行 Java 应用程序一直存在一个问题,那就是在容器中运行的 JVM 程序在设置内存大小和 CPU 使用率后,会导致应用程序的性能下降。这是因为 Java 应用程序没有意识到它正在容器中运行。随着 Java10 的发布,这个问题总算得以解诀, JVM 现在可以识别由容器控制组 ( cgroups ) 设置的约束,可以在容器中使用内存和 CPU 约束来直接管理 Java 应用程序,其中包括:

  • 遵守容器中设置的内存限制
  • 在容器中设置可用的 CPU
  • 在容器中设置 CPU 约束

# 支持 Unicode 10

Unicode 10 新增了 8518 个字符,总计达到了 136690 个字符。包括 56 个新的 emoji 表情符号。

JDK11java.lang 下增加了 4 个类来处理:

  • CharacterData00.class
  • CharacterData01.class
  • CharacterData02.class
  • CharacterData0E.class

# 新支持的加密算法

Java 实现了 RFC7539 中指定的 ChaCha20Poly1305 两种加密算法,代替 RC4
RFC7748 定义的密钥协商方案更高效,更安全, JDK 增加了两个新的接口 XECPublicKeyXECPrivateKey

# 垃圾回收器

# ZGC

启用方法: -XX:+UnlockExperimentalVMOptions -XX:+UseZGC

说明: ZGC , A Scalable Low-Latency Garbage collector ( Experimental ) ,一个可伸缩的低延时的垃圾回收器。 GC 暂停时间不会超过 10ms ,既能处理几百兆的小堆,也能处理几个 T 的大堆。和 G1 相比,应用吞吐能力不会下降超过 15% ,为未来的 GC 功能和利用 colord 指针以及 Load barriers 优化奠定了基础。初始只支持 64 位系统。

ZGC 的设计目标是:支持 TB 级内存容量,暂停时间低 ( <10ms ),对整个程序吞吐量的影响小于 15% 。将来还可以扩 展实现机制,以支持不少令人兴奋的功能,例如多层堆 (即热对象置于 DRAM 和冷对象置于 NVMe 闪存),或压缩堆。

GCjava 主要优势之一。然而,当 GC 停顿太长,就会开始影响应用的响应时间。消除或者减少 GC 停顿时长, java 将有可能在更广泛的应用场景中成长为一个更有吸引力的平台。此外,现代系统中可用内存不断增长,用户和程序员希望 JVM 能够以高效的方式充分利用这些内存,并且无需长时间的 GC 暂停时间。

ZGC 是一个并发,基于 region , 压缩型的垃圾收集器,只有 root 扫描阶段会 STW , 因此 GC 停顿时间不会随着堆的增长和存活对象的增长而变长。

# Epsilon

实验性质,生产环境不建议使用。

启用方法: -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC

说明:开发一个处理内存分配但不实现任何实际内存回收机制的 GC , 一旦可用堆内存用完, JVM 就会退出,如果有 System.gc() 调用,实际上什么也不会发生 (这种场景下和 -XX:+DisableExplicitGC 效果一样), 因为没有内存回收,这个实现可能会警告用户尝试强制 GC 是徒劳的。

主要用途如下:

  • 性能测试 (它可以帮助过滤掉 GC 引起的性能假象)
  • 内存压力测试 (例如,知道测试用例应该分配不超过 1GB 的内存,我们可以使用 -Xmx1g -XX:+UseEpsilonGC ,如果程序有问题,则程序会崩溃。
  • 非常短的 JOB 任务 (对于这种任务, GC 是在浪费资源)
  • VM 接口测试
  • Last-drop 延迟 & 吞吐改进

# 更好的 G1

对于 G1 GC , 相比于 JDK8 , 升级到 JDK 11 即可免费享受到:并行的 Full GC , 快速的 CardTable 扫描,自适应的堆占用比例调整 ( IHOP ), 在并发标记阶段的类型卸载等等。这些都是针对 G1 的不断增强,其中串行 FullGC 等甚至是曾经被广泛诟病的短板,你会发现 GC 配置和调优在 JDK11 中越来越方便。

# 移除与不再推荐使用的类库或功能

Jdk9Jdk11 ,陆续移除了一些类库或功能。

# 移除了 Java EE 和 CORBA Moudles

java11 中移除了不太使用的 JavaEE 模块和 CORBA 技术。

CORBA 来自于二十世纪九十年代, Oracle 认为,现在用 CORBA 开发现代 Java 应用程序已经没有意义了,维护 CORBA 的成本已经超过了保留它带来的好处。

但是删除 CORBA 将使得那些依赖于 JDK 提供部分 CORBAAPICORBA 实现无法运行。目前还没有第三方 CORBA 版本,也不确定是否会有第三方愿意接手 CORBA API 的维护工作。

java11 中将 java9 标记废弃的 Java EECORBA 模块移除掉,具体如下:

xml 相关被移除的:

  • java.xml.ws
  • java.xml.bind
  • java.xml.ws
  • java.xml.ws.annotation
  • jdk.xml.bind
  • jdk.xml.ws

只剩下 java.xml , java.xml.crypto.jdk.xml.dom 这几个模块。

其它被移除的 Java EE 和 CORBA 相关类库:

  • java.corba
  • java.se.ee
  • java.activation
  • java.transaction (但是 java11 新增了一个 java.transaction.xa 模块)

# 其他移除的类库

  • com.sun.awt.AWTUtilities
  • sun.miss.Unsafe.defineClass
  • Thread.destroy() 以及 Thread.stop(Throwable) 方法
  • sun.nio.ch.disableSystemWideOverlappingFileLockCheck 属性
  • sun.locale.formatasdefault 属性
  • jdk snmp 模块
  • javafx
  • java Mission Control
  • Root Certificates : 一些根证书被移除: Baltimore Cybertrust Code Signing CA, SECOM Root Certificate, AOL and Swisscom Root Certificates

其中,使用 java.lang.invoke.MethodHandles.Lookup.defineClass 来替代移除的 sun.miss.Unsafe.defineClass

# 将 Nashorn Javascript 标记为不推荐

Javascript 引擎标记为 Deprecate ,后续版本会移除,有需要的可以考虑使用开源的 GraalVM

# 将 Pack200 Tools and API 标记为不推荐

java11 中将 pack200 以及 unpack200 工具以及 java.tiljar 中的 Pack200 API 标记为 Deprecate 。因为 Pack200 主要是用来压缩 jar 包的工具,由于网络下载速度的提升以及 java9 引入模块化系统之后不再依赖 Pack200 ,因此这个版本将其标记为 Deprecate

# 预告

LTS JDK8 之后,又一 LTS , 你会用吗? JDK16 , 它来了。

# 对了

JDK11JDK8 的代码?

代码始终是代码,写的再多,写不懂你我。

多看一点,就比其他们多懂一点。所以,你关不关注我,问题不大!

人情世故。不是世故,就是事故。问题真的不大。

文中所有代码,在 https://gitee.com/fangjiaxiaobai/learn_java/tree/master/fxb_jdk11

# 最后

希望和你一起遇见更好的自己

更新于 阅读次数

请我喝[咖啡]~( ̄▽ ̄)~*

方小白 微信支付

微信支付

方小白 支付宝

支付宝

方小白 numberpay

numberpay