1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00
Java-Interview-Guide/docs/java/jdk-new-features/new-features-from-jdk8-to-jdk14.md
2020-04-20 15:28:00 +08:00

16 KiB
Raw Blame History

Guide 哥:别人家的特性都用了几年了,我 Java 才出来,哈哈!真实!

Java9

发布于 2017 年 9 月 21 日 。作为 Java8 之后 3 年半才发布的新版本Java 9 带 来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流、

Java 平台模块系统

  • Java 平台模块系统,也就是 Project Jigsaw把模块化开发实践引入到了 Java 平台中。在引入了模块系统之后JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具,创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。
  • Java 9 模块的重要特征是在其工件artifact的根目录中包含了一个描述模块的 module-info.class 文 件。 工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。

Jshell

  • jshell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具
  • 在 Jshell 中可以直接输入表达式并查看其执行结果

集合、Stream 和 Optional

  • 增加 了 List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合,比如List.of("Java", "C++");Map.of("Java", 1, "C++", 2);(这部分内容有点参考 Guava 的味道)
  • Stream 中增加了新的方法 ofNullabledropWhiletakeWhileiterate 方法。Collectors 中增加了新的方法 filteringflatMapping
  • Optional 类中新增了 ifPresentOrElseorstream 等方法

进程 API

  • Java 9 增加了 ProcessHandle 接口,可以对原生进程进行管理,尤其适合于管理长时间运行的进程

平台日志 API 和服务

  • Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。

  • 可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。

反应式流 Reactive Streams

  • 在 Java9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口
  • Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

变量句柄

  • 变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等
  • 变量句柄的含义类似于已有的方法句柄MethodHandle
  • 由 Java 类java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对 象

改进方法句柄Method Handle

  • 方法句柄从 Java7 开始引入Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄

其它新特性

  • 接口私有方法 Java 9 允许在接口中使用私有方法

  • try-with-resources 增强 :在 try-with-resources 语句中可以使用 effectively-final 变量(什么是 effectively-final 变量,见这篇文章 http://ilkinulas.github.io/programming/java/2016/03/27/effectively-final-java.html

  • CompletableFuture 中增加了几个新的方法(completeAsync orTimeout 等)

  • Nashorn 引擎的增强Nashorn 从 Java8 开始引入的 JavaScript 引擎Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性

  • I/O 流的新特性:增加了新的方法来读取和复制 InputStream 中包含的数据

  • 改进应用的安全性能Java 9 新增了 4 个 SHA- 3 哈希算法SHA3-224、SHA3-256、SHA3-384 和 S HA3-512

Java10

发布于 2018 年 3 月 20 日,最知名的特性应该是 var 关键字局部变量类型推断的引入了其他还有垃圾收集器改善、GC 改进、性能提升、线程管控等一批新特性

var 关键字

  • 使用 :提供了 var 关键字声明局部变量:var list = new ArrayList<String>(); // ArrayList<String>
  • 局限性 :只能用于带有构造器的局部变量和 for 循环中

Guide 哥:实际上 Lombok 早就体用了一个类似的关键字,使用它可以简化代码,但是可能会降低程序的易读性、可维护性。一般情况下,我个人都不太推荐使用。

不可变集合

  • listsetmap 提供了静态方法copyOf()返回一个入参集合的一个不可变拷贝
  • java.util.stream.Collectors中新增了静态方法,收集为不可变集合

Optional

  • 新增了orElseThrow()方法来在没有值时抛出异常

并行全垃圾回收器 G1

从 Java9 开始 G1 就了默认的垃圾回收器G1 是以一种低延时的垃圾回收器来设计的,旨在避免进行 Full GC,但是 Java9 的 G1 的 FullGC 依然是使用单线程去完成标记清除算法,这可能会导致垃圾回收期在无法回收内存的时候触发 Full GC。

为了最大限度地减少 Full GC 造成的应用停顿的影响,从 Java10 开始G1 的 FullGC 改为并行的标记清除算法,同时会使用与年轻代回收和混合回收相同的并行工作线程数量,从而减少了 Full GC 的发生,以带来更好的性能提升、更大的吞吐量。

应用程序类数据共享

  • 在 Java 5 中就已经引入了类数据共享机制 (Class Data Sharing简称 CDS),允许将一组类预处理为共享归档文件,以便在运行时能够进行内存映射以减少 Java 程序的启动时间,当多个 Java 虚拟机JVM共享相同的归档文件时还可以减少动态内存的占用量同时减少多个虚拟机在同一个物理或虚拟的机器上运行时的资源占用
  • Java 10 在现有的 CDS 功能基础上再次拓展以允许应用类放置在共享存档中。CDS 特性在原来的 bootstrap 类基础之上,扩展加入了应用类的 CDS (Application Class-Data Sharing) 支持。其原理为:在启动时记录加载类的过程,写入到文本文件中,再次启动时直接读取此启动文本并加载。设想如果应用环境没有大的变化,启动速度就会得到提升

其他特性

  • 线程-局部管控Java 10 中线程管控引入 JVM 安全点的概念,将允许在不运行全局 JVM 安全点的情况下实现线程回调,由线程本身或者 JVM 线程来执行,同时保持线程处于阻塞状态,这种方式使得停止单个线程变成可能,而不是只能启用或停止所有线程

  • 备用存储装置上的堆分配Java 10 中将使得 JVM 能够使用适用于不同类型的存储机制的堆,在可选内存设备上进行堆内存分配

  • 统一的垃圾回收接口Java 10 中hotspot/gc 代码实现方面,引入一个干净的 GC 接口,改进不同 GC 源代码的隔离性,多个 GC 之间共享的实现细节代码应该存在于辅助类中。统一垃圾回收接口的主要原因是让垃圾回收器GC这部分代码更加整洁便于新人上手开发便于后续排查相关问题。

Java11

Java11 于 2018 年 9 月 25 日正式发布这是很重要的一个版本Java 11 和 2017 年 9 月份发布的 Java 9 以及 2018 年 3 月份发布的 Java 10 相比,其最大的区别就是:在长期支持(Long-Term-Support)方面,Oracle 表示会对 Java 11 提供大力支持,这一支持将会持续至 2026 年 9 月。这是据 Java 8 以后支持的首个长期版本。

字符串加强

Java 11 增加了一系列的字符串处理方法,如以下所示。

Guide 哥说白点就是多了层封装JDK 开发组的人没少看市面上常见的工具类框架啊!

//判断字符串是否为空
" ".isBlank();//true
//去除字符串首尾空格
" Java ".strip();// "Java" 
//去除字符串首部空格
" Java ".stripLeading();   // "Java "  
//去除字符串尾部空格
" Java ".stripTrailing();  // " Java"  
//重复字符串多少次
"Java".repeat(3);             // "JavaJavaJava"  

//返回由行终止符分隔的字符串集合。
"A\nB\nC".lines().count();    // 3 
"A\nB\nC".lines().collect(Collectors.toList()); 

ZGC可伸缩低延迟垃圾收集器

  • ZGC 即 Z Garbage Collector,是一个可伸缩的、低延迟的垃圾收集器。
  • 主要为了满足如下目标进行设计:
    • GC 停顿时间不超过 10ms
    • 即能处理几百 MB 的小堆,也能处理几个 TB 的大堆
    • 应用吞吐能力不会下降超过 15%(与 G1 回收算法相比)
    • 方便在此基础上引入新的 GC 特性和利用 colord
    • 针以及 Load barriers 优化奠定基础
    • 当前只支持 Linux/x64 位平台
  • 处在实验阶段,只支持 Linux/x64 平台

标准 HTTP Client 升级

  • Java 11 对 Java 9 中引入并在 Java 10 中进行了更新的 Http Client API 进行了标准化在前两个版本中进行孵化的同时Http Client 几乎被完全重写,并且现在完全支持异步非阻塞
  • Java11 中Http Client 的包名由 jdk.incubator.http 改为java.net.http,该 API 通过 CompleteableFuture 提供非阻塞请求和响应语义。

使用起来也很简单,如下:

var request = HttpRequest.newBuilder()  

    .uri(URI.create("https://javastack.cn"))  

    .GET()  

    .build();  

var client = HttpClient.newHttpClient();  

// 同步  

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());  

System.out.println(response.body());  

// 异步  

client.sendAsync(request, HttpResponse.BodyHandlers.ofString())  

    .thenApply(HttpResponse::body)  

    .thenAccept(System.out::println); 


简化启动单个源代码文件的方法

  • 增强了 Java 启动器,使其能够运行单一文件的 Java 源代码。此功能允许使用 Java 解释器直接执行 Java 源代码。源代码在内存中编译,然后由解释器执行。唯一的约束在于所有相关的类必须定义在同一个 Java 文件中
  • 对于 Java 初学者并希望尝试简单程序的人特别有用,并且能和 jshell 一起使用
  • 一定能程度上增强了使用 Java 来写脚本程序的能力

用于 Lambda 参数的局部变量语法

  • 从 Java 10 开始,便引入了局部变量类型推断这一关键特性。类型推断允许使用关键字 var 作为局部变量的类型而不是实际类型,编译器根据分配给变量的值推断出类型
  • Java 10 中对 var 关键字存在几个限制
    • 只能用于局部变量上
    • 声明时必须初始化
    • 不能用作方法参数
    • 不能在 Lambda 表达式中使用
  • Java11 开始允许开发者在 Lambda 表达式中使用 var 进行参数声明

其他特性

  • 新的垃圾回收器 Epsilon一个完全消极的 GC 实现,分配有限的内存资源,最大限度的降低内存占用和内存吞吐延迟时间
  • 低开销的 Heap ProfilingJava 11 中提供一种低开销的 Java 堆分配采样方法,能够得到堆分配的 Java 对象信息,并且能够通过 JVMTI 访问堆信息
  • TLS1.3 协议Java 11 中包含了传输层安全性TLS1.3 规范RFC 8446的实现替换了之前版本中包含的 TLS包括 TLS 1.2,同时还改进了其他 TLS 功能,例如 OCSP 装订扩展RFC 6066RFC 6961以及会话散列和扩展主密钥扩展RFC 7627在安全性和性能方面也做了很多提升
  • 飞行记录器:飞行记录器之前是商业版 JDK 的一项分析工具,但在 Java 11 中,其代码被包含到公开代码库中,这样所有人都能使用该功能了

Java12

增强 Switch

  • 传统的 switch 语法存在容易漏写 break 的问题,而且从代码整洁性层面来看,多个 break 本质也是一种重复
  • Java12 提供了 swtich 表达式,使用类似 lambda 语法条件匹配成功后的执行块,不需要多写 break

Shenandoah GC

  • Redhat 主导开发的 Pauseless GC 实现,主要目标是 99.9% 的暂停小于 10ms暂停与堆大小无关等
  • 和 Java11 开源的 ZGC 相比(需要升级到 JDK11 才能使用Shenandoah GC 有稳定的 JDK8u 版本,在 Java8 占据主要市场份额的今天有更大的可落地性

G1 收集器提升

  • Java12 为默认的垃圾收集器 G1 带来了两项更新
    • 可中止的混合收集集合JEP344 的实现为了达到用户提供的停顿时间目标JEP 344 通过把要被回收的区域集(混合收集集合)拆分为强制和可选部分,使 G1 垃圾回收器能中止垃圾回收过程。 G1 可以中止可选部分的回收以达到停顿时间目标
    • 及时返回未使用的已分配内存JEP346 的实现,增强 G1 GC以便在空闲时自动将 Java 堆内存返回给操作系统

Java13

引入 yield 关键字到 Switch 中

  • Switch 表达式中就多了一个关键字用于跳出 Switch 块的关键字 yield,主要用于返回一个值
  • yieldreturn 的区别在于:return 会直接跳出当前循环或者方法,而 yield 只会跳出当前 Switch 块,同时在使用 yield 时,需要有 default 条件

文本块

  • 解决 Java 定义多行字符串时只能通过换行转义或者换行连接符来变通支持的问题,引入三重双引号来定义多行文本
  • 两个"""中间的任何内容都会被解释为字符串的一部分,包括换行符

增强 ZGC 释放未使用内存

  • 在 Java 11 中是实验性的引入的 ZGC 在实际的使用中存在未能主动将未使用的内存释放给操作系统的问题
  • ZGC 堆由一组称为 ZPages 的堆区域组成。在 GC 周期中清空 ZPages 区域时,它们将被释放并返回到页面缓存 ZPageCache 中,此缓存中的 ZPages 按最近最少使用LRU的顺序并按照大小进行组织
  • 在 Java 13 中ZGC 将向操作系统返回被标识为长时间未使用的页面,这样它们将可以被其他进程重用

SocketAPI 重构

  • Java 13 为 Socket API 带来了新的底层实现方法,并且在 Java 13 中是默认使用新的 Socket 实现,使其易于发现并在排除问题同时增加可维护性

动态应用程序类-数据共享

  • Java 13 中对 Java 10 中引入的 应用程序类数据共享进行了进一步的简化、改进和扩展,即:允许在 Java 应用程序执行结束时动态进行类归档,具体能够被归档的类包括:所有已被加载,但不属于默认基层 CDS 的应用程序类和引用类库中的类

Java14

record 关键字

  • 简化数据类的定义方式,使用 record 代替 class 定义的类,只需要声明属性,就可以在获得属性的访问方法,以及 toStringhashCode,equals 方法
  • 类似于使用 Class 定义类,同时使用了 lomobok 插件,并打上了@Getter,@ToString,@EqualsAndHashCode注解

空指针异常精准提示

  • 通过 JVM 参数中添加-XX:+ShowCodeDetailsInExceptionMessages,可以在空指针异常中获取更为详细的调用信息,更快的定位和解决问题

switch 的增强终于转正

  • JDK12 引入的 switch预览特性在 JDK14 变为正式版本
  • 主要是用->来替代以前的:+break;另外就是提供了 yield 来在 block 中返回值

instanceof 增强

  • instanceof 主要在类型强转前探测对象的具体类型,然后执行具体的强转

  • 新版的 instanceof 可以在判断的是否属于具体的类型同时完成转换

Object obj = "我是字符串";
if(obj instanceof String str){
	System.out.println(str);
}

参考信息