入职新公司两个月了,用 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 EE 和 CORBA 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
}

# 不兼容的类型赋值

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

# 不能推测的类型

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

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

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

# Collection 增强

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

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

Set 和 List 的用法类似。 同样的,也是不可变集合。需要注意的是, 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 是第三个参数,第二个参数是 Prediction 。 Prediction 中进行判断的取值是迭代之后的数值。

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 System , java 平台模块系统,简称 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 信息. exports 将 com.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 提供了一个新的工具 jshell , Java 终于可以像 python , scala 等语言那样,交互式演示语法了

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

# Low-Overhead Heap Profiling

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

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

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

# 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.1 和 HTTP2 , websocket 协议
  • 支持同步和异步编程模型
  • 将请求和响应主体作为响应式流 ( reactive-streams ) 处理,并使用构建器模式
  • 要发送 http 请求,首先要使用其构建器创建一个 HttpClient 。这个构建器能够配置每个客户端的状态:
    • 首选协议版本 ( HTTP/1.1 或 HTTP/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 。

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

HttpRequest 和 HttpResponse 还提供了转换器,用于将 java.util.concurrent.Flow 的 Publisher/Subscriber 类型转换为 HTTP Client 的 BodyPublisher/BodySubscriber 类型。

# 请求协议 HTTP/2

Java HTTP Client 支持 HTTP/1.1 和 HTTP/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 表情符号。

JDK11 在 java.lang 下增加了 4 个类来处理:

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

# 新支持的加密算法

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

# 垃圾回收器

# 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 闪存),或压缩堆。

GC 是 java 主要优势之一。然而,当 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 中越来越方便。

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

Jdk9 到 Jdk11 ,陆续移除了一些类库或功能。

# 移除了 Java EE 和 CORBA Moudles

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

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

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

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

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 , 它来了。

# 对了

JDK11 写 JDK8 的代码?

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

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

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

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

# 最后

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

更新于 阅读次数 次

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

方小白 微信支付

微信支付

方小白 支付宝

支付宝

方小白 numberpay

numberpay