你们好,我是Guide哥!这篇文章来自读者的投稿,通过了两次较大的改动,两周的完善终于完成。Java 8新特性见这里:Java8新特性最佳指南 。html
Guide 哥:别人家的特性都用了几年了,我 Java 才出来,哈哈!真实!java
发布于 2017 年 9 月 21 日 。做为 Java8 以后 3 年半才发布的新版本,Java 9 带 来了不少重大的变化其中最重要的改动是 Java 平台模块系统的引入,其余还有诸如集合、Stream 流linux
Java 平台模块系统,也就是 Project Jigsaw,把模块化开发实践引入到了 Java 平台中。在引入了模块系统以后,JDK 被从新组织成 94 个模块。Java 应用能够经过新增的 jlink 工具,建立出只包含所依赖的 JDK 模块的自定义运行时镜像。这样能够极大的减小 Java 运行时环境的大小。git
Java 9 模块的重要特征是在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文 件。 工件的格式能够是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。github
jshell 是 Java 9 新增的一个实用工具。为 Java 提供了相似于 Python 的实时命令行交互工具。web
在 Jshell 中能够直接输入表达式并查看其执行结果算法
List.of()
、
Set.of()
、
Map.of()
和
Map.ofEntries()
等工厂方法来建立不可变集合,好比
List.of("Java", "C++");
、
Map.of("Java", 1, "C++", 2)
;(这部份内容有点参考 Guava 的味道)
Stream
中增长了新的方法
ofNullable
、
dropWhile
、
takeWhile
和
iterate
方法。
Collectors
中增长了新的方法
filtering
和
flatMapping
Optional
类中新增了
ifPresentOrElse
、
or
和
stream
等方法
Java 9 增长了 ProcessHandle
接口,能够对原生进程进行管理,尤为适合于管理长时间运行的进程shell
Java 9 容许为 JDK 和应用配置一样的日志实现。新增了 System.LoggerFinder
用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder
实例。json
咱们能够经过添加本身的 System.LoggerFinder
实现来让 JDK 和应用使用 SLF4J 等其余日志记录框架。bootstrap
java.util.concurrent.Flow
类中新增了反应式流规范的核心接口
Flow.Publisher
、
Flow.Subscriber
、
Flow.Subscription
和
Flow.Processor
等 4 个核心接口。Java 9 还提供了
SubmissionPublisher
做为
Flow.Publisher
的一个实现。
MethodHandle
java.lang.invoke.VarHandle
来表示,可使用类
java.lang.invoke.MethodHandles.Lookup
中的静态工厂方法来建立
VarHandle
对 象
java.lang.invoke.MethodHandles
中新增了更多的静态方法来建立不一样类型的方法句柄
CompletableFuture
中增长了几个新的方法(completeAsync
,orTimeout
等)
发布于 2018 年 3 月 20 日,最知名的特性应该是 var 关键字(局部变量类型推断)的引入了,其余还有垃圾收集器改善、GC 改进、性能提高、线程管控等一批新特性
var list = new ArrayList<String>(); // ArrayList<String>
Guide 哥:实际上 Lombok 早就体用了一个相似的关键字,使用它能够简化代码,可是可能会下降程序的易读性、可维护性。通常状况下,我我的都不太推荐使用。
list,set,map 提供了静态方法copyOf()
返回入参集合的一个不可变拷贝(如下为 JDK 的源码)
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
复制代码
java.util.stream.Collectors
中新增了静态方法,用于将流中的元素收集为不可变的集合
orElseThrow()
方法来在没有值时抛出异常
从 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 于 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 即 Z Garbage Collector,是一个可伸缩的、低延迟的垃圾收集器。
ZGC 主要为了知足以下目标进行设计:
ZGC 目前 处在实验阶段,只支持 Linux/x64 平台
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);
复制代码
传统的 switch 语法存在容易漏写 break 的问题,并且从代码整洁性层面来看,多个 break 本质也是一种重复
Java12 提供了 swtich 表达式,使用相似 lambda 语法条件匹配成功后的执行块,不须要多写 break
做为预览特性加入,须要在javac
编译和java
运行时增长参数--enable-preview
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
复制代码
NumberFormat
新增了对复杂的数字进行格式化的支持
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
String result = fmt.format(1000);
System.out.println(result); // 输出为 1K,计算工资是多少K更方便了。。。
复制代码
Switch
表达式中就多了一个关键字用于跳出 Switch
块的关键字 yield
,主要用于返回一个值
yield
和 return
的区别在于:return
会直接跳出当前循环或者方法,而 yield
只会跳出当前 Switch
块,同时在使用 yield
时,须要有 default
条件
private static String descLanguage(String name) {
return switch (name) {
case "Java": yield "object-oriented, platform independent and secured";
case "Ruby": yield "a programmer's best friend";
default: yield name +" is a good language";
};
}
复制代码
解决 Java 定义多行字符串时只能经过换行转义或者换行链接符来变通支持的问题,引入三重双引号来定义多行文本
两个"""
中间的任何内容都会被解释为字符串的一部分,包括换行符
String json ="{\n" +
" \"name\":\"mkyong\",\n" +
" \"age\":38\n" +
"}\n"; // 未支持文本块以前
复制代码
String json = """
{
"name":"mkyong",
"age":38
}
""";
复制代码
简化数据类的定义方式,使用 record 代替 class 定义的类,只须要声明属性,就能够在得到属性的访问方法,以及 toString,hashCode,equals 方法
相似于使用 Class 定义类,同时使用了 lomobok 插件,并打上了@Getter,@ToString,@EqualsAndHashCode
注解
做为预览特性引入
/**
* 这个类具备两个特征
* 1. 全部成员属性都是final
* 2. 所有方法由构造方法,和两个成员属性访问器组成(共三个)
* 那么这种类就很适合使用record来声明
*/
final class Rectangle implements Shape {
final double length;
final double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
double length() { return length; }
double width() { return width; }
}
/**
* 1. 使用record声明的类会自动拥有上面类中的三个方法
* 2. 在这基础上还附赠了equals(),hashCode()方法以及toString()方法
* 3. toString方法中包括全部成员属性的字符串表示形式及其名称
*/
record Rectangle(float length, float width) { }
复制代码
经过 JVM 参数中添加-XX:+ShowCodeDetailsInExceptionMessages
,能够在空指针异常中获取更为详细的调用信息,更快的定位和解决问题
a.b.c.i = 99; // 假设这段代码会发生空指针
复制代码
Exception in thread "main" java.lang.NullPointerException:
Cannot read field 'c' because 'a.b' is null.
at Prog.main(Prog.java:5) // 增长参数后提示的异常中很明确的告知了哪里为空致使
复制代码
->
来替代之前的
:
+
break
;另外就是提供了 yield 来在 block 中返回值
Before Java 14
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
复制代码
Java 14 enhancements
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
复制代码
instanceof 主要在类型强转前探测对象的具体类型,而后执行具体的强转
新版的 instanceof 能够在判断的是否属于具体的类型同时完成转换
Object obj = "我是字符串";
if(obj instanceof String str){
System.out.println(str);
}
复制代码
deb
和
rpm
,window 平台下的
msi
和
exe
This is a preview feature, which is a feature whose design, specification, and implementation are complete, but is not permanent, which means that the feature may exist in a different form or not at all in future JDK releases. To compile and run code that contains preview features, you must specify additional command-line options.
switch
的加强为例子,从 Java12 中推出,到 Java13 中将继续加强,直到 Java14 才正式转正进入 JDK 能够放心使用,不用考虑后续 JDK 版本对其的改动或修改
本文使用 mdnice 排版