mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-08-14 05:21:42 +08:00
Compare commits
No commits in common. "e44be8e524f0858b1e69b7e072d0981a67d26097" and "29b7417b021644dab4423345cfad55fd6fd49ce7" have entirely different histories.
e44be8e524
...
29b7417b02
@ -122,8 +122,7 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
|
||||
- [Java 10 新特性概览](./docs/java/new-features/java10.md)
|
||||
- [Java 11 新特性概览](./docs/java/new-features/java11.md)
|
||||
- [Java 12~13 新特性概览](./docs/java/new-features/java12-13.md)
|
||||
- [Java 14 新特性概览](./docs/java/new-features/java14.md)
|
||||
- [Java 15 新特性概览](./docs/java/new-features/java15.md)
|
||||
- [Java 14~15 新特性概览](./docs/java/new-features/java14-15.md)
|
||||
- [Java 16 新特性概览](./docs/java/new-features/java16.md)
|
||||
- [Java 18 新特性概览](./docs/java/new-features/java18.md)
|
||||
- [Java 19 新特性概览](./docs/java/new-features/java19.md)
|
||||
|
@ -145,10 +145,8 @@ export const sidebarConfig = defineSidebarConfig({
|
||||
"java10",
|
||||
"java11",
|
||||
"java12-13",
|
||||
"java14",
|
||||
"java15",
|
||||
"java14-15",
|
||||
"java16",
|
||||
"java17",
|
||||
"java18",
|
||||
"java19",
|
||||
],
|
||||
|
@ -126,10 +126,8 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
|
||||
- [Java 10 新特性概览](./java/new-features/java10.md)
|
||||
- [Java 11 新特性概览](./java/new-features/java11.md)
|
||||
- [Java 12~13 新特性概览](./java/new-features/java12-13.md)
|
||||
- [Java 14 新特性概览](./java/new-features/java14.md)
|
||||
- [Java 15 新特性概览](./java/new-features/java15.md)
|
||||
- [Java 14~15 新特性概览](./java/new-features/java14-15.md)
|
||||
- [Java 16 新特性概览](./java/new-features/java16.md)
|
||||
- [Java 17 新特性概览](./java/new-features/java17.md)
|
||||
- [Java 18 新特性概览](./java/new-features/java18.md)
|
||||
- [Java 19 新特性概览](./java/new-features/java19.md)
|
||||
|
||||
|
@ -1,11 +1,129 @@
|
||||
---
|
||||
title: Java 15 新特性概览
|
||||
title: Java 14 ~ 15 新特性概览
|
||||
category: Java
|
||||
tag:
|
||||
- Java新特性
|
||||
---
|
||||
|
||||
## CharSequence
|
||||
## Java14
|
||||
|
||||
### 空指针异常精准提示
|
||||
|
||||
通过 JVM 参数中添加`-XX:+ShowCodeDetailsInExceptionMessages`,可以在空指针异常中获取更为详细的调用信息,更快的定位和解决问题。
|
||||
|
||||
```java
|
||||
a.b.c.i = 99; // 假设这段代码会发生空指针
|
||||
```
|
||||
|
||||
Java 14 之前:
|
||||
|
||||
```java
|
||||
Exception in thread "main" java.lang.NullPointerException
|
||||
at NullPointerExample.main(NullPointerExample.java:5)
|
||||
```
|
||||
|
||||
Java 14 之后:
|
||||
|
||||
```java
|
||||
// 增加参数后提示的异常中很明确的告知了哪里为空导致
|
||||
Exception in thread "main" java.lang.NullPointerException:
|
||||
Cannot read field 'c' because 'a.b' is null.
|
||||
at Prog.main(Prog.java:5)
|
||||
```
|
||||
|
||||
### switch 的增强(转正)
|
||||
|
||||
Java12 引入的 switch(预览特性)在 Java14 变为正式版本,不需要增加参数来启用,直接在 JDK14 中就能使用。
|
||||
|
||||
Java12 为 switch 表达式引入了类似 lambda 语法条件匹配成功后的执行块,不需要多写 break ,Java13 提供了 `yield` 来在 block 中返回值。
|
||||
|
||||
```java
|
||||
String result = switch (day) {
|
||||
case "M", "W", "F" -> "MWF";
|
||||
case "T", "TH", "S" -> "TTS";
|
||||
default -> {
|
||||
if(day.isEmpty())
|
||||
yield "Please insert a valid day.";
|
||||
else
|
||||
yield "Looks like a Sunday.";
|
||||
}
|
||||
|
||||
};
|
||||
System.out.println(result);
|
||||
```
|
||||
|
||||
### 预览新特性
|
||||
|
||||
#### record 关键字
|
||||
|
||||
`record` 关键字可以简化 **数据类**(一个 Java 类一旦实例化就不能再修改)的定义方式,使用 `record` 代替 `class` 定义的类,只需要声明属性,就可以在获得属性的访问方法,以及 `toString()`,`hashCode()`, `equals()`方法
|
||||
|
||||
类似于使用 `class` 定义类,同时使用了 lombok 插件,并打上了`@Getter,@ToString,@EqualsAndHashCode`注解
|
||||
|
||||
```java
|
||||
/**
|
||||
* 这个类具有两个特征
|
||||
* 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) { }
|
||||
```
|
||||
|
||||
#### 文本块
|
||||
|
||||
Java14 中,文本块依然是预览特性,不过,其引入了两个新的转义字符:
|
||||
|
||||
- `\` : 表示行尾,不引入换行符
|
||||
- `\s` :表示单个空格
|
||||
|
||||
```java
|
||||
String str = "凡心所向,素履所往,生如逆旅,一苇以航。";
|
||||
|
||||
String str2 = """
|
||||
凡心所向,素履所往, \
|
||||
生如逆旅,一苇以航。""";
|
||||
System.out.println(str2);// 凡心所向,素履所往, 生如逆旅,一苇以航。
|
||||
String text = """
|
||||
java
|
||||
c++\sphp
|
||||
""";
|
||||
System.out.println(text);
|
||||
//输出:
|
||||
java
|
||||
c++ php
|
||||
```
|
||||
|
||||
#### instanceof 增强
|
||||
|
||||
依然是**预览特性** ,Java 12 新特性中介绍过。
|
||||
|
||||
### Java14 其他特性
|
||||
|
||||
- 从 Java11 引入的 ZGC 作为继 G1 过后的下一代 GC 算法,从支持 Linux 平台到 Java14 开始支持 MacOS 和 Window(个人感觉是终于可以在日常开发工具中先体验下 ZGC 的效果了,虽然其实 G1 也够用)
|
||||
- 移除了 CMS(Concurrent Mark Sweep) 垃圾收集器(功成而退)
|
||||
- 新增了 jpackage 工具,标配将应用打成 jar 包外,还支持不同平台的特性包,比如 linux 下的`deb`和`rpm`,window 平台下的`msi`和`exe`
|
||||
|
||||
## Java15
|
||||
|
||||
### CharSequence
|
||||
|
||||
`CharSequence` 接口添加了一个默认方法 `isEmpty()` 来判断字符序列为空,如果是则返回 true。
|
||||
|
||||
@ -17,7 +135,7 @@ public interface CharSequence {
|
||||
}
|
||||
```
|
||||
|
||||
## TreeMap
|
||||
### TreeMap
|
||||
|
||||
`TreeMap` 新引入了下面这些方法:
|
||||
|
||||
@ -27,7 +145,7 @@ public interface CharSequence {
|
||||
- `compute()`
|
||||
- `merge()`
|
||||
|
||||
## ZGC(转正)
|
||||
### ZGC(转正)
|
||||
|
||||
Java11 的时候 ,ZGC 还在试验阶段。
|
||||
|
||||
@ -41,7 +159,7 @@ Java11 的时候 ,ZGC 还在试验阶段。
|
||||
$ java -XX:+UseZGC className
|
||||
```
|
||||
|
||||
## EdDSA(数字签名算法)
|
||||
### EdDSA(数字签名算法)
|
||||
|
||||
新加入了一个安全性和性能都更强的基于 Edwards-Curve Digital Signature Algorithm (EdDSA)实现的数字签名算法。
|
||||
|
||||
@ -68,26 +186,25 @@ System.out.println(encodedString);
|
||||
0Hc0lxxASZNvS52WsvnncJOH/mlFhnA8Tc6D/k5DtAX5BSsNVjtPF4R4+yMWXVjrvB2mxVXmChIbki6goFBgAg==
|
||||
```
|
||||
|
||||
## 文本块(转正)
|
||||
### 文本块(转正)
|
||||
|
||||
在 Java 15 ,文本块是正式的功能特性了。
|
||||
|
||||
## 隐藏类(Hidden Classes)
|
||||
### 隐藏类(Hidden Classes)
|
||||
|
||||
隐藏类是为框架(frameworks)所设计的,隐藏类不能直接被其他类的字节码使用,只能在运行时生成类并通过反射间接使用它们。
|
||||
|
||||
## 预览新特性
|
||||
### 预览新特性
|
||||
|
||||
### 密封类
|
||||
#### 密封类
|
||||
|
||||
**密封类(Sealed Classes)** 是 Java 15 中的一个预览新特性。
|
||||
Java 15 对 Java 14 中引入的预览新特性进行了增强,主要是引入了一个新的概念 **密封类(Sealed Classes)。**
|
||||
|
||||
没有密封类之前,在 Java 中如果想让一个类不能被继承和修改,我们可以使用`final` 关键字对类进行修饰。不过,这种方式不太灵活,直接把一个类的继承和修改渠道给堵死了。
|
||||
密封类可以对继承或者实现它们的类进行限制。
|
||||
|
||||
密封类可以对继承或者实现它们的类进行限制,这样这个类就只能被指定的类继承。
|
||||
比如抽象类 `Person` 只允许 `Employee` 和 `Manager` 继承。
|
||||
|
||||
```java
|
||||
// 抽象类 Person 只允许 Employee 和 Manager 继承。
|
||||
public abstract sealed class Person
|
||||
permits Employee, Manager {
|
||||
|
||||
@ -109,13 +226,13 @@ public non-sealed class Manager extends Person {
|
||||
|
||||
如果允许扩展的子类和封闭类在同一个源代码文件里,封闭类可以不使用 permits 语句,Java 编译器将检索源文件,在编译期为封闭类添加上许可的子类。
|
||||
|
||||
### instanceof 模式匹配
|
||||
#### instanceof 模式匹配
|
||||
|
||||
Java 15 并没有对此特性进行调整,继续预览特性,主要用于接受更多的使用反馈。
|
||||
|
||||
在未来的 Java 版本中,Java 的目标是继续完善 `instanceof` 模式匹配新特性。
|
||||
|
||||
## Java15 其他新特性
|
||||
### Java15 其他新特性
|
||||
|
||||
- **Nashorn JavaScript 引擎彻底移除** :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性。在 Java 11 中就已经被弃用,到了 Java 15 就彻底被删除了。
|
||||
- **DatagramSocket API 重构**
|
||||
@ -140,4 +257,11 @@ Java 15 并没有对此特性进行调整,继续预览特性,主要用于接
|
||||
|
||||
整体优化的方向是**高效,低时延的垃圾回收表现**
|
||||
|
||||
对于日常的应用开发者可能比较关注新的语法特性,但是从一个公司角度来说,在考虑是否升级 Java 平台时更加考虑的是**JVM 运行时的提升**
|
||||
对于日常的应用开发者可能比较关注新的语法特性,但是从一个公司角度来说,在考虑是否升级 Java 平台时更加考虑的是**JVM 运行时的提升**
|
||||
|
||||
## 参考
|
||||
|
||||
- Oracle Java14 record <https://docs.oracle.com/en/java/javase/14/language/records.html>
|
||||
- java14-features <https://www.techgeeknext.com/java/java14-features>
|
||||
- Java 14 Features : <https://www.journaldev.com/37273/java-14-features>
|
||||
- What is new in Java 15: https://mkyong.com/java/what-is-new-in-java-15/
|
@ -1,120 +0,0 @@
|
||||
---
|
||||
title: Java 14 新特性概览
|
||||
category: Java
|
||||
tag:
|
||||
- Java新特性
|
||||
---
|
||||
|
||||
## 空指针异常精准提示
|
||||
|
||||
通过 JVM 参数中添加`-XX:+ShowCodeDetailsInExceptionMessages`,可以在空指针异常中获取更为详细的调用信息,更快的定位和解决问题。
|
||||
|
||||
```java
|
||||
a.b.c.i = 99; // 假设这段代码会发生空指针
|
||||
```
|
||||
|
||||
Java 14 之前:
|
||||
|
||||
```java
|
||||
Exception in thread "main" java.lang.NullPointerException
|
||||
at NullPointerExample.main(NullPointerExample.java:5)
|
||||
```
|
||||
|
||||
Java 14 之后:
|
||||
|
||||
```java
|
||||
// 增加参数后提示的异常中很明确的告知了哪里为空导致
|
||||
Exception in thread "main" java.lang.NullPointerException:
|
||||
Cannot read field 'c' because 'a.b' is null.
|
||||
at Prog.main(Prog.java:5)
|
||||
```
|
||||
|
||||
## switch 的增强(转正)
|
||||
|
||||
Java12 引入的 switch(预览特性)在 Java14 变为正式版本,不需要增加参数来启用,直接在 JDK14 中就能使用。
|
||||
|
||||
Java12 为 switch 表达式引入了类似 lambda 语法条件匹配成功后的执行块,不需要多写 break ,Java13 提供了 `yield` 来在 block 中返回值。
|
||||
|
||||
```java
|
||||
String result = switch (day) {
|
||||
case "M", "W", "F" -> "MWF";
|
||||
case "T", "TH", "S" -> "TTS";
|
||||
default -> {
|
||||
if(day.isEmpty())
|
||||
yield "Please insert a valid day.";
|
||||
else
|
||||
yield "Looks like a Sunday.";
|
||||
}
|
||||
|
||||
};
|
||||
System.out.println(result);
|
||||
```
|
||||
|
||||
## 预览新特性
|
||||
|
||||
### record 关键字
|
||||
|
||||
`record` 关键字可以简化 **数据类**(一个 Java 类一旦实例化就不能再修改)的定义方式,使用 `record` 代替 `class` 定义的类,只需要声明属性,就可以在获得属性的访问方法,以及 `toString()`,`hashCode()`, `equals()`方法
|
||||
|
||||
类似于使用 `class` 定义类,同时使用了 lombok 插件,并打上了`@Getter,@ToString,@EqualsAndHashCode`注解
|
||||
|
||||
```java
|
||||
/**
|
||||
* 这个类具有两个特征
|
||||
* 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) { }
|
||||
```
|
||||
|
||||
### 文本块
|
||||
|
||||
Java14 中,文本块依然是预览特性,不过,其引入了两个新的转义字符:
|
||||
|
||||
- `\` : 表示行尾,不引入换行符
|
||||
- `\s` :表示单个空格
|
||||
|
||||
```java
|
||||
String str = "凡心所向,素履所往,生如逆旅,一苇以航。";
|
||||
|
||||
String str2 = """
|
||||
凡心所向,素履所往, \
|
||||
生如逆旅,一苇以航。""";
|
||||
System.out.println(str2);// 凡心所向,素履所往, 生如逆旅,一苇以航。
|
||||
String text = """
|
||||
java
|
||||
c++\sphp
|
||||
""";
|
||||
System.out.println(text);
|
||||
//输出:
|
||||
java
|
||||
c++ php
|
||||
```
|
||||
|
||||
### instanceof 增强
|
||||
|
||||
依然是**预览特性** ,Java 12 新特性中介绍过。
|
||||
|
||||
## Java14 其他特性
|
||||
|
||||
- 从 Java11 引入的 ZGC 作为继 G1 过后的下一代 GC 算法,从支持 Linux 平台到 Java14 开始支持 MacOS 和 Window(个人感觉是终于可以在日常开发工具中先体验下 ZGC 的效果了,虽然其实 G1 也够用)
|
||||
- 移除了 CMS(Concurrent Mark Sweep) 垃圾收集器(功成而退)
|
||||
- 新增了 jpackage 工具,标配将应用打成 jar 包外,还支持不同平台的特性包,比如 linux 下的`deb`和`rpm`,window 平台下的`msi`和`exe`
|
@ -5,105 +5,11 @@ tag:
|
||||
- Java新特性
|
||||
---
|
||||
|
||||
Java 16 在 2021 年 3 月 16 日正式发布,非长期支持(LTS)版本。
|
||||
## Java 16
|
||||
|
||||
相关阅读:[OpenJDK Java 16 文档](https://openjdk.java.net/projects/jdk/16/) 。
|
||||
### 记录类型(转正)
|
||||
|
||||
## JEP 338:向量 API(第二次孵化)
|
||||
|
||||
向量(Vector) API 最初由 [JEP 338](https://openjdk.java.net/jeps/338) 提出,并作为[孵化 API](http://openjdk.java.net/jeps/11)集成到 Java 16 中。第二轮孵化由 [JEP 414](https://openjdk.java.net/jeps/414) 提出并集成到 Java 17 中,第三轮孵化由 [JEP 417](https://openjdk.java.net/jeps/417) 提出并集成到 Java 18 中,第四轮由 [JEP 426](https://openjdk.java.net/jeps/426) 提出并集成到了 Java 19 中。
|
||||
|
||||
该孵化器 API 提供了一个 API 的初始迭代以表达一些向量计算,这些计算在运行时可靠地编译为支持的 CPU 架构上的最佳向量硬件指令,从而获得优于同等标量计算的性能,充分利用单指令多数据(SIMD)技术(大多数现代 CPU 上都可以使用的一种指令)。尽管 HotSpot 支持自动向量化,但是可转换的标量操作集有限且易受代码更改的影响。该 API 将使开发人员能够轻松地用 Java 编写可移植的高性能向量算法。
|
||||
|
||||
在 [Java 18 新特性概览](./java18.md) 中,我有详细介绍到向量 API,这里就不再做额外的介绍了。
|
||||
|
||||
## JEP 347:启用 C++ 14 语言特性
|
||||
|
||||
Java 16 允许在 JDK 的 C++ 源代码中使用 C++14 语言特性,并提供在 HotSpot 代码中可以使用哪些特性的具体指导。
|
||||
|
||||
在 Java 15 中,JDK 中 C++ 代码使用的语言特性仅限于 C++98/03 语言标准。它要求更新各种平台编译器的最低可接受版本。
|
||||
|
||||
## JEP 376:ZGC 并发线程堆栈处理
|
||||
|
||||
Java16 将 ZGC 线程栈处理从安全点转移到一个并发阶段,甚至在大堆上也允许在毫秒内暂停 GC 安全点。消除 ZGC 垃圾收集器中最后一个延迟源可以极大地提高应用程序的性能和效率。
|
||||
|
||||
## JEP 387:弹性元空间
|
||||
|
||||
自从引入了 Metaspace 以来,根据反馈,Metaspace 经常占用过多的堆外内存,从而导致内存浪费。弹性元空间这个特性可将未使用的 HotSpot 类元数据(即元空间,metaspace)内存更快速地返回到操作系统,从而减少元空间的占用空间。
|
||||
|
||||
并且,这个提案还简化了元空间的代码以降低维护成本。
|
||||
|
||||
## JEP 390:对基于值的类发出警告
|
||||
|
||||
> 以下介绍摘自:[实操 | 剖析 Java16 新语法特性](https://xie.infoq.cn/article/8304c894c4e38318d38ceb116),原文写的很不错,推荐阅读。
|
||||
|
||||
早在 Java9 版本时,Java 的设计者们就对 `@Deprecated` 注解进行了一次升级,增加了 `since` 和 `forRemova`l 等 2 个新元素。其中,since 元素用于指定标记了 `@Deprecated` 注解的 API 被弃用时的版本,而 `forRemoval` 则进一步明确了 API 标记 @Deprecated 注解时的语义,如果`forRemoval=true`时,则表示该 API 在未来版本中肯定会被删除,开发人员应该使用新的 API 进行替代,不再容易产生歧义(Java9 之前,标记 @Deprecated 注解的 API,语义上存在多种可能性,比如:存在使用风险、可能在未来存在兼容性错误、可能在未来版本中被删除,以及应该使用更好的替代方案等)。
|
||||
|
||||
仔细观察原始类型的包装类(比如:`java.lang.Integer`、`java.lang.Double`),不难发现,其构造函数上都已经标记有`@Deprecated(since="9", forRemoval = true)`注解,这就意味着其构造函数在将来会被删除,不应该在程序中继续使用诸如`new Integer();`这样的编码方式(建议使用`Integer a = 10;`或者`Integer.valueOf()`函数),如果继续使用,编译期将会产生'Integer(int)' is deprecated and marked for removal 告警。并且,值得注意的是,这些包装类型已经被指定为同 `java.util.Optional` 和 `java.time.LocalDateTime` 一样的值类型。
|
||||
|
||||
其次,如果继续在 `synchronized` 同步块中使用值类型,将会在编译期和运行期产生警告,甚至是异常。在此大家需要注意,就算编译期和运行期没有产生警告和异常,也不建议在 `synchronized` 同步块中使用值类型,举个自增的例子。示例 1-5:
|
||||
|
||||
```java
|
||||
public void inc(Integer count) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
new Thread(() -> {
|
||||
synchronized (count) {
|
||||
count++;
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当执行上述程序示例时,最终的输出结果一定会与你的期望产生差异,这是许多新人经常犯错的一个点,因为在并发环境下,`Integer` 对象根本无法通过 `synchronized` 来保证线程安全,这是因为每次的`count++`操作,所产生的 `hashcode` 均不同,简而言之,每次加锁都锁在了不同的对象上。因此,如果希望在实际的开发过程中保证其原子性,应该使用 `AtomicInteger`。
|
||||
|
||||
## JEP 392:打包工具
|
||||
|
||||
在 Java 14 中,JEP 343 引入了打包工具,命令是 `jpackage`。在 Java 15 中,继续孵化,现在在 Java 16 中,终于成为了正式功能。
|
||||
|
||||
这个打包工具允许打包自包含的 Java 应用程序。它支持原生打包格式,为最终用户提供自然的安装体验,这些格式包括 Windows 上的 msi 和 exe、macOS 上的 pkg 和 dmg,还有 Linux 上的 deb 和 rpm。它还允许在打包时指定启动时参数,并且可以从命令行直接调用,也可以通过 ToolProvider API 以编程方式调用。注意 jpackage 模块名称从 jdk.incubator.jpackage 更改为 jdk.jpackage。这将改善最终用户在安装应用程序时的体验,并简化了“应用商店”模型的部署。
|
||||
|
||||
关于这个打包工具的实际使用,可以看这个视频 [Playing with Java 16 jpackage](https://www.youtube.com/watch?v=KahYIVzRIkQ)(需要梯子)。
|
||||
|
||||
## JEP 393:外部内存访问 API(第三次孵化)
|
||||
|
||||
引入外部内存访问 API 以允许 Java 程序安全有效地访问 Java 堆之外的外部内存。
|
||||
|
||||
Java 14([ JEP 370](https://openjdk.org/jeps/370)) 的时候,第一次孵化外部内存访问 API,Java 15 中进行了第二次复活([JEP 383](https://openjdk.org/jeps/383)),在 Java 16 中进行了第三次孵化。
|
||||
|
||||
引入外部内存访问 API 的目的如下:
|
||||
|
||||
- 通用:单个 API 应该能够对各种外部内存(如本机内存、持久内存、堆内存等)进行操作。
|
||||
- 安全:无论操作何种内存,API 都不应该破坏 JVM 的安全性。
|
||||
- 控制:可以自由的选择如何释放内存(显式、隐式等)。
|
||||
- 可用:如果需要访问外部内存,API 应该是 `sun.misc.Unsafa`.
|
||||
|
||||
## JEP 394:instanceof 模式匹配(转正)
|
||||
|
||||
| JDK 版本 | 更新类型 | JEP | 更新内容 |
|
||||
| ---------- | ----------------- | --------------------------------------- | ---------------------------------------- |
|
||||
| Java SE 14 | preview | [JEP 305](https://openjdk.org/jeps/305) | 首次引入 instanceof 模式匹配。 |
|
||||
| Java SE 15 | Second Preview | [JEP 375](https://openjdk.org/jeps/375) | 相比较上个版本无变化,继续收集更多反馈。 |
|
||||
| Java SE 16 | Permanent Release | [JEP 394](https://openjdk.org/jeps/394) | 模式变量不在隐式为 final。 |
|
||||
|
||||
从 Java 16 开始,你可以对 `instanceof` 中的变量值进行修改。
|
||||
|
||||
```java
|
||||
// Old code
|
||||
if (o instanceof String) {
|
||||
String s = (String)o;
|
||||
... use s ...
|
||||
}
|
||||
|
||||
// New code
|
||||
if (o instanceof String s) {
|
||||
... use s ...
|
||||
}
|
||||
```
|
||||
|
||||
## JEP 395:记录类型(转正)
|
||||
|
||||
记录类型变更历史:
|
||||
变更历史:
|
||||
|
||||
| JDK 版本 | 更新类型 | JEP | 更新内容 |
|
||||
| ---------- | ----------------- | -------------------------------------------- | ------------------------------------------------------------ |
|
||||
@ -123,28 +29,49 @@ public class Outer {
|
||||
|
||||
> 在 JDK 16 之前,如果写上面这种代码,IDE 会提示你静态字段 age 不能在非静态的内部类中定义,除非它用一个常量表达式初始化。(The field age cannot be declared static in a non-static inner type, unless initialized with a constant expression)
|
||||
|
||||
## JEP 396:默认强封装 JDK 内部元素
|
||||
### instanceof 模式匹配(转正)
|
||||
|
||||
此特性会默认强封装 JDK 的所有内部元素,但关键内部 API(例如 `sun.misc.Unsafe`)除外。默认情况下,使用早期版本成功编译的访问 JDK 内部 API 的代码可能不再起作用。鼓励开发人员从使用内部元素迁移到使用标准 API 的方法上,以便他们及其用户都可以无缝升级到将来的 Java 版本。强封装由 JDK 9 的启动器选项–illegal-access 控制,到 JDK 15 默认改为 warning,从 JDK 16 开始默认为 deny。(目前)仍然可以使用单个命令行选项放宽对所有软件包的封装,将来只有使用–add-opens 打开特定的软件包才行。
|
||||
| JDK 版本 | 更新类型 | JEP | 更新内容 |
|
||||
| ---------- | ----------------- | --------------------------------------- | ---------------------------------------- |
|
||||
| Java SE 14 | preview | [JEP 305](https://openjdk.org/jeps/305) | 首次引入 instanceof 模式匹配。 |
|
||||
| Java SE 15 | Second Preview | [JEP 375](https://openjdk.org/jeps/375) | 相比较上个版本无变化,继续收集更多反馈。 |
|
||||
| Java SE 16 | Permanent Release | [JEP 394](https://openjdk.org/jeps/394) | 模式变量不在隐式为 final。 |
|
||||
|
||||
## JEP 397:密封类(预览)
|
||||
从 Java SE 16 开始,你可以对 instanceof 中的变量值进行修改。
|
||||
|
||||
密封类由 [JEP 360](https://openjdk.java.net/jeps/360) 提出预览,集成到了 Java 15 中。在 JDK 16 中, 密封类得到了改进(更加严格的引用检查和密封类的继承关系),由 [JEP 397](https://openjdk.java.net/jeps/397) 提出了再次预览。
|
||||
```java
|
||||
public void learn(Object obj) {
|
||||
if (obj instanceof String s) {
|
||||
System.out.println(s);
|
||||
s = "JavaGuide";
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在 [Java 15 新特性概览](./java15.md) 中,我有详细介绍到密封类,这里就不再做额外的介绍了。
|
||||
### 预览新特性
|
||||
|
||||
## 其他优化与改进
|
||||
#### 密封类
|
||||
|
||||
- **JEP 380:Unix-Domain 套接字通道** :Unix-domain 套接字一直是大多数 Unix 平台的一个特性,现在在 Windows 10 和 Windows Server 2019 也提供了支持。此特性为 java.nio.channels 包的套接字通道和服务器套接字通道 API 添加了 Unix-domain(AF_UNIX)套接字支持。它扩展了继承的通道机制以支持 Unix-domain 套接字通道和服务器套接字通道。Unix-domain 套接字用于同一主机上的进程间通信(IPC)。它们在很大程度上类似于 TCP/IP,区别在于套接字是通过文件系统路径名而不是 Internet 协议(IP)地址和端口号寻址的。对于本地进程间通信,Unix-domain 套接字比 TCP/IP 环回连接更安全、更有效
|
||||
- **JEP 389:外部链接器 API(孵化) :**该孵化器 API 提供了静态类型、纯 Java 访问原生代码的特性,该 API 将大大简化绑定原生库的原本复杂且容易出错的过程。Java 1.1 就已通过 Java 原生接口(JNI)支持了原生方法调用,但并不好用。Java 开发人员应该能够为特定任务绑定特定的原生库。它还提供了外来函数支持,而无需任何中间的 JNI 粘合代码。
|
||||
- **JEP 357:从 Mercurial 迁移到 Git** :在此之前,OpenJDK 源代码是使用版本管理工具 Mercurial 进行管理,现在迁移到了 Git。
|
||||
- **JEP 369:迁移到 GitHub**:和 JEP 357 从 Mercurial 迁移到 Git 的改变一致,在把版本管理迁移到 Git 之后,选择了在 GitHub 上托管 OpenJDK 社区的 Git 仓库。不过只对 JDK 11 以及更高版本 JDK 进行了迁移。
|
||||
- **JEP 386:移植 Alpine Linux** :Apine Linux 是一个独立的、非商业的 Linux 发行版,它十分的小,一个容器需要不超过 8MB 的空间,最小安装到磁盘只需要大约 130MB 存储空间,并且十分的简单,同时兼顾了安全性。此提案将 JDK 移植到了 Apline Linux,由于 Apline Linux 是基于 musl lib 的轻量级 Linux 发行版,因此其他 x64 和 AArch64 架构上使用 musl lib 的 Linux 发行版也适用。
|
||||
- **JEP 388:Windows/AArch64 移植** :这些 JEP 的重点不是移植工作本身,而是将它们集成到 JDK 主线存储库中;JEP 386 将 JDK 移植到 Alpine Linux 和其他使用 musl 作为 x64 上主要 C 库的发行版上。此外,JEP 388 将 JDK 移植到 Windows AArch64(ARM64)。
|
||||
在 JDK 15 引入的 sealed class(密封类)在 JDK 16 得到了改进:更加严格的引用检查和密封类的继承关系。
|
||||
|
||||
## 参考文献
|
||||
### 其他优化与改进
|
||||
|
||||
- **优化 JavaDoc 的搜索功能** :对于单词大小写问题的改进,当不知道具体拼写或者大小写的时候很有用。
|
||||
- **ZGC 并发线程处理** :JEP 376 将 ZGC 线程栈处理从安全点转移到一个并发阶段,甚至在大堆上也允许在毫秒内暂停 GC 安全点。消除 ZGC 垃圾收集器中最后一个延迟源可以极大地提高应用程序的性能和效率。
|
||||
- **弹性元空间** :此特性可将未使用的 HotSpot 类元数据(即元空间,metaspace)内存更快速地返回到操作系统,从而减少元空间的占用空间。具有大量类加载和卸载活动的应用程序可能会占用大量未使用的空间。新方案将元空间内存按较小的块分配,它将未使用的元空间内存返回给操作系统来提高弹性,从而提高应用程序性能并降低内存占用。
|
||||
- **Unix-Domain 套接字通道** :Unix-domain 套接字一直是大多数 Unix 平台的一个特性,现在在 Windows 10 和 Windows Server 2019 也提供了支持。此特性为 java.nio.channels 包的套接字通道和服务器套接字通道 API 添加了 Unix-domain(AF_UNIX)套接字支持。它扩展了继承的通道机制以支持 Unix-domain 套接字通道和服务器套接字通道。Unix-domain 套接字用于同一主机上的进程间通信(IPC)。它们在很大程度上类似于 TCP/IP,区别在于套接字是通过文件系统路径名而不是 Internet 协议(IP)地址和端口号寻址的。对于本地进程间通信,Unix-domain 套接字比 TCP/IP 环回连接更安全、更有效。
|
||||
- **打包工具**:此特性最初是作为 Java 14 中的一个孵化器模块引入的,该工具允许打包自包含的 Java 应用程序。它支持原生打包格式,为最终用户提供自然的安装体验,这些格式包括 Windows 上的 msi 和 exe、macOS 上的 pkg 和 dmg,还有 Linux 上的 deb 和 rpm。它还允许在打包时指定启动时参数,并且可以从命令行直接调用,也可以通过 ToolProvider API 以编程方式调用。注意 jpackage 模块名称从 jdk.incubator.jpackage 更改为 jdk.jpackage。这将改善最终用户在安装应用程序时的体验,并简化了“应用商店”模型的部署。
|
||||
- **对基于值的类发出警告**:此特性将原始包装器类(java.lang.Integer、java.lang.Double 等)指定为基于值的(类似于 java.util.Optional 和 java.time.LocalDateTime),并在其构造器中添加 forRemoval(自 JDK 9 开始被弃用),这样会提示新的警告。在 Java 平台中尝试在任何基于值的类的实例上进行不正确的同步时,它会发出警告。
|
||||
- **默认强封装 JDK 内部元素**:此特性会默认强封装 JDK 的所有内部元素,但关键内部 API(例如 sun.misc.Unsafe)除外。默认情况下,使用早期版本成功编译的访问 JDK 内部 API 的代码可能不再起作用。鼓励开发人员从使用内部元素迁移到使用标准 API 的方法上,以便他们及其用户都可以无缝升级到将来的 Java 版本。强封装由 JDK 9 的启动器选项–illegal-access 控制,到 JDK 15 默认改为 warning,从 JDK 16 开始默认为 deny。(目前)仍然可以使用单个命令行选项放宽对所有软件包的封装,将来只有使用–add-opens 打开特定的软件包才行。
|
||||
- **向量 API(孵化器)**:该孵化器 API 提供了一个 API 的初始迭代以表达一些向量计算,这些计算在运行时可靠地编译为支持的 CPU 架构上的最佳向量硬件指令,从而获得优于同等标量计算的性能,充分利用单指令多数据(SIMD)技术(大多数现代 CPU 上都可以使用的一种指令)。尽管 HotSpot 支持自动向量化,但是可转换的标量操作集有限且易受代码更改的影响。该 API 将使开发人员能够轻松地用 Java 编写可移植的高性能向量算法。
|
||||
- **外部链接器 API(孵化器)**:该孵化器 API 提供了静态类型、纯 Java 访问原生代码的特性,该 API 将大大简化绑定原生库的原本复杂且容易出错的过程。Java 1.1 就已通过 Java 原生接口(JNI)支持了原生方法调用,但并不好用。Java 开发人员应该能够为特定任务绑定特定的原生库。它还提供了外来函数支持,而无需任何中间的 JNI 粘合代码。
|
||||
- **外部存储器访问 API**:在 Java 14 和 Java 15 中作为孵化器 API 引入的这个 API 使 Java 程序能够安全有效地对各种外部存储器(例如本机存储器、持久性存储器、托管堆存储器等)进行操作。它提供了外部链接器 API 的基础。
|
||||
- **启用 C++14 语言特性** :它允许在 JDK C++ 源代码中使用 C++14 语言特性,并提供在 HotSpot 代码中可以使用哪些特性的具体指导。在 JDK 15 中,JDK 中 C++ 代码使用的语言特性仅限于 C++98/03 语言标准。它要求更新各种平台编译器的最低可接受版本。
|
||||
- **AlpineLinux 移植;JEP 388,Windows/AArch64 移植** :这些 JEP 的重点不是移植工作本身,而是将它们集成到 JDK 主线存储库中;JEP 386 将 JDK 移植到 Alpine Linux 和其他使用 musl 作为 x64 上主要 C 库的发行版上。此外,JEP 388 将 JDK 移植到 Windows AArch64(ARM64)。
|
||||
|
||||
### 参考文献
|
||||
|
||||
- [Java Language Changes](https://docs.oracle.com/en/java/javase/16/language/java-language-changes.html)
|
||||
- [Consolidated JDK 16 Release Notes](https://www.oracle.com/java/technologies/javase/16all-relnotes.html)
|
||||
- [Java 16 正式发布,新特性一一解析](https://www.infoq.cn/article/IAkwhx7i9V7G8zLVEd4L)
|
||||
- [实操 | 剖析 Java16 新语法特性](https://xie.infoq.cn/article/8304c894c4e38318d38ceb116)(写的很赞)
|
||||
|
@ -1,164 +0,0 @@
|
||||
---
|
||||
title: Java 17 新特性概览
|
||||
category: Java
|
||||
tag:
|
||||
- Java新特性
|
||||
---
|
||||
|
||||
Java 17 在 2021 年 9 月 14 日正式发布,Java 17 是一个长期支持(LTS)版本,这次更新共带来 14 个新特性:
|
||||
|
||||
- [JEP 306:Restore Always-Strict Floating-Point Semantics(恢复始终严格的浮点语义)](https://openjdk.java.net/jeps/306)
|
||||
- [JEP 356:Enhanced Pseudo-Random Number Generators(增强的伪随机数生成器)](https://openjdk.java.net/jeps/356)
|
||||
- [JEP 382:New macOS Rendering Pipeline(新的 macOS 渲染管道)](https://openjdk.java.net/jeps/382)
|
||||
- [JEP 391:macOS/AArch64 Port(支持 macOS AArch64)](https://openjdk.java.net/jeps/391)
|
||||
- [JEP 398:Deprecate the Applet API for Removal(删除已弃用的 Applet API)](https://openjdk.java.net/jeps/398)
|
||||
- [JEP 403:Strongly Encapsulate JDK Internals(更强大的封装 JDK 内部元素)](https://openjdk.java.net/jeps/403)
|
||||
- [JEP 406:Pattern Matching for switch (switch 的类型匹配)](https://openjdk.java.net/jeps/406)(预览)
|
||||
- [JEP 407:Remove RMI Activation(删除远程方法调用激活机制)](https://openjdk.java.net/jeps/407)
|
||||
- [JEP 409:Sealed Classes(密封类)](https://openjdk.java.net/jeps/409)(转正)
|
||||
- [JEP 410:Remove the Experimental AOT and JIT Compiler(删除实验性的 AOT 和 JIT 编译器)](https://openjdk.java.net/jeps/410)
|
||||
- [JEP 411:Deprecate the Security Manager for Removal(弃用安全管理器以进行删除)](https://openjdk.java.net/jeps/411)
|
||||
- [JEP 412:Foreign Function & Memory API (外部函数和内存 API)](https://openjdk.java.net/jeps/412)(孵化)
|
||||
- [JEP 414:Vector(向量) API ](https://openjdk.java.net/jeps/417)(第二次孵化)
|
||||
- [JEP 415:Context-Specific Deserialization Filters](https://openjdk.java.net/jeps/415)
|
||||
|
||||
这里只对 356、398、413、406、407、409、410、411、412、414 这几个我觉得比较重要的新特性进行详细介绍。
|
||||
|
||||
相关阅读:[OpenJDK Java 17 文档](https://openjdk.java.net/projects/jdk/17/) 。
|
||||
|
||||
## JEP 356:增强的伪随机数生成器
|
||||
|
||||
JDK 17 之前,我们可以借助 `Random`、`ThreadLocalRandom`和`SplittableRandom`来生成随机数。不过,这 3 个类都各有缺陷,且缺少常见的伪随机算法支持。
|
||||
|
||||
Java 17 为伪随机数生成器 (pseudorandom number generator,RPNG,又称为确定性随机位生成器)增加了新的接口类型和实现,使得开发者更容易在应用程序中互换使用各种 PRNG 算法。
|
||||
|
||||
> [RPNG](https://ctf-wiki.org/crypto/streamcipher/prng/intro/) 用来生成接近于绝对随机数序列的数字序列。一般来说,PRNG 会依赖于一个初始值,也称为种子,来生成对应的伪随机数序列。只要种子确定了,PRNG 所生成的随机数就是完全确定的,因此其生成的随机数序列并不是真正随机的。
|
||||
|
||||
使用示例:
|
||||
|
||||
```java
|
||||
RandomGeneratorFactory<RandomGenerator> l128X256MixRandom = RandomGeneratorFactory.of("L128X256MixRandom");
|
||||
// 使用时间戳作为随机数种子
|
||||
RandomGenerator randomGenerator = l128X256MixRandom.create(System.currentTimeMillis());
|
||||
// 生成随机数
|
||||
randomGenerator.nextInt(10));
|
||||
```
|
||||
|
||||
## JEP 398:弃用 Applet API 以进行删除
|
||||
|
||||
Applet API 用于编写在 Web 浏览器端运行的 Java 小程序,很多年前就已经被淘汰了,已经没有理由使用了。
|
||||
|
||||
Applet API 在 Java 9 时被标记弃用([JEP 289](https://openjdk.java.net/jeps/289)),但不是为了删除。
|
||||
|
||||
## JEP 406:switch 的类型匹配(预览)
|
||||
|
||||
正如 `instanceof` 一样, `switch` 也紧跟着增加了类型匹配自动转换功能。
|
||||
|
||||
`instanceof` 代码示例:
|
||||
|
||||
```java
|
||||
// Old code
|
||||
if (o instanceof String) {
|
||||
String s = (String)o;
|
||||
... use s ...
|
||||
}
|
||||
|
||||
// New code
|
||||
if (o instanceof String s) {
|
||||
... use s ...
|
||||
}
|
||||
```
|
||||
|
||||
`switch` 代码示例:
|
||||
|
||||
```java
|
||||
// Old code
|
||||
static String formatter(Object o) {
|
||||
String formatted = "unknown";
|
||||
if (o instanceof Integer i) {
|
||||
formatted = String.format("int %d", i);
|
||||
} else if (o instanceof Long l) {
|
||||
formatted = String.format("long %d", l);
|
||||
} else if (o instanceof Double d) {
|
||||
formatted = String.format("double %f", d);
|
||||
} else if (o instanceof String s) {
|
||||
formatted = String.format("String %s", s);
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
// New code
|
||||
static String formatterPatternSwitch(Object o) {
|
||||
return switch (o) {
|
||||
case Integer i -> String.format("int %d", i);
|
||||
case Long l -> String.format("long %d", l);
|
||||
case Double d -> String.format("double %f", d);
|
||||
case String s -> String.format("String %s", s);
|
||||
default -> o.toString();
|
||||
};
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
对于 `null` 值的判断也进行了优化。
|
||||
|
||||
```java
|
||||
// Old code
|
||||
static void testFooBar(String s) {
|
||||
if (s == null) {
|
||||
System.out.println("oops!");
|
||||
return;
|
||||
}
|
||||
switch (s) {
|
||||
case "Foo", "Bar" -> System.out.println("Great");
|
||||
default -> System.out.println("Ok");
|
||||
}
|
||||
}
|
||||
|
||||
// New code
|
||||
static void testFooBar(String s) {
|
||||
switch (s) {
|
||||
case null -> System.out.println("Oops");
|
||||
case "Foo", "Bar" -> System.out.println("Great");
|
||||
default -> System.out.println("Ok");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## JEP 407:删除远程方法调用激活机制
|
||||
|
||||
删除远程方法调用 (RMI) 激活机制,同时保留 RMI 的其余部分。RMI 激活机制已过时且不再使用。
|
||||
|
||||
## JEP 409:密封类(转正)
|
||||
|
||||
密封类由 [JEP 360](https://openjdk.java.net/jeps/360) 提出预览,集成到了 Java 15 中。在 JDK 16 中, 密封类得到了改进(更加严格的引用检查和密封类的继承关系),由 [JEP 397](https://openjdk.java.net/jeps/397) 提出了再次预览。
|
||||
|
||||
在 [Java 15 新特性概览](./java15.md) 中,我有详细介绍到密封类,这里就不再做额外的介绍了。
|
||||
|
||||
## JEP 410:删除实验性的 AOT 和 JIT 编译器
|
||||
|
||||
在 Java 9 的 [JEP 295](https://openjdk.java.net/jeps/295) ,引入了实验性的提前 (AOT) 编译器,在启动虚拟机之前将 Java 类编译为本机代码。
|
||||
|
||||
Java 17,删除实验性的提前 (AOT) 和即时 (JIT) 编译器,因为该编译器自推出以来很少使用,维护它所需的工作量很大。保留实验性的 Java 级 JVM 编译器接口 (JVMCI),以便开发人员可以继续使用外部构建的编译器版本进行 JIT 编译。
|
||||
|
||||
## JEP 411:弃用安全管理器以进行删除
|
||||
|
||||
弃用安全管理器以便在将来的版本中删除。
|
||||
|
||||
安全管理器可追溯到 Java 1.0,多年来,它一直不是保护客户端 Java 代码的主要方法,也很少用于保护服务器端代码。为了推动 Java 向前发展,Java 17 弃用安全管理器,以便与旧版 Applet API ( [JEP 398](https://openjdk.java.net/jeps/398) ) 一起移除。
|
||||
|
||||
## JEP 412:外部函数和内存 API(孵化)
|
||||
|
||||
Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。
|
||||
|
||||
外部函数和内存 API 在 Java 17 中进行了第一轮孵化,由 [JEP 412](https://openjdk.java.net/jeps/412) 提出。第二轮孵化由[ JEP 419](https://openjdk.org/jeps/419) 提出并集成到了 Java 18 中,预览由 [JEP 424](https://openjdk.org/jeps/424) 提出并集成到了 Java 19 中。
|
||||
|
||||
在 [Java 19 新特性概览](./java19.md) 中,我有详细介绍到外部函数和内存 API,这里就不再做额外的介绍了。
|
||||
|
||||
## JEP 414:向量 API(第二次孵化)
|
||||
|
||||
向量(Vector) API 最初由 [JEP 338](https://openjdk.java.net/jeps/338) 提出,并作为[孵化 API](http://openjdk.java.net/jeps/11)集成到 Java 16 中。第二轮孵化由 [JEP 414](https://openjdk.java.net/jeps/414) 提出并集成到 Java 17 中,第三轮孵化由 [JEP 417](https://openjdk.java.net/jeps/417) 提出并集成到 Java 18 中,第四轮由 [JEP 426](https://openjdk.java.net/jeps/426) 提出并集成到了 Java 19 中。
|
||||
|
||||
该孵化器 API 提供了一个 API 的初始迭代以表达一些向量计算,这些计算在运行时可靠地编译为支持的 CPU 架构上的最佳向量硬件指令,从而获得优于同等标量计算的性能,充分利用单指令多数据(SIMD)技术(大多数现代 CPU 上都可以使用的一种指令)。尽管 HotSpot 支持自动向量化,但是可转换的标量操作集有限且易受代码更改的影响。该 API 将使开发人员能够轻松地用 Java 编写可移植的高性能向量算法。
|
||||
|
||||
在 [Java 18 新特性概览](./java18.md) 中,我有详细介绍到向量 API,这里就不再做额外的介绍了。
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Java 18 新特性概览
|
||||
title: Java 19 新特性概览
|
||||
category: Java
|
||||
tag:
|
||||
- Java新特性
|
||||
@ -19,7 +19,7 @@ Java 18 在 2022 年 3 月 22 日正式发布,非长期支持版本。Java 18
|
||||
|
||||
Java 17 中包含 14 个特性,Java 16 中包含 17 个特性,Java 15 中包含 14 个特性,Java 14 中包含 16 个特性。相比于前面发布的版本来说,Java 18 的新特性少了很多。
|
||||
|
||||
这里只对 400、408、413、416、417、418、419 这几个我觉得比较重要的新特性进行详细介绍。
|
||||
这里只对 400、408、413、416、418 这 5 个我觉得比较重要的新特性进行详细介绍。在 [Java 19 新特性概览](./java19.md)这篇文章中,我详细介绍了 Vector(向量) API 和 Foreign Function & Memory API(外部函数和内存 API),感兴趣的可以看看,这里就不重复讲了。
|
||||
|
||||
相关阅读:
|
||||
|
||||
@ -80,58 +80,6 @@ OpenJDK 官方给出了新老实现的反射性能基准测试结果。
|
||||
|
||||

|
||||
|
||||
## JEP 417: 向量 API(第三次孵化)
|
||||
|
||||
向量(Vector) API 最初由 [JEP 338](https://openjdk.java.net/jeps/338) 提出,并作为[孵化 API](http://openjdk.java.net/jeps/11)集成到 Java 16 中。第二轮孵化由 [JEP 414](https://openjdk.java.net/jeps/414) 提出并集成到 Java 17 中,第三轮孵化由 [JEP 417](https://openjdk.java.net/jeps/417) 提出并集成到 Java 18 中,第四轮由 [JEP 426](https://openjdk.java.net/jeps/426) 提出并集成到了 Java 19 中。
|
||||
|
||||
向量计算由对向量的一系列操作组成。向量 API 用来表达向量计算,该计算可以在运行时可靠地编译为支持的 CPU 架构上的最佳向量指令,从而实现优于等效标量计算的性能。
|
||||
|
||||
向量 API 的目标是为用户提供简洁易用且与平台无关的表达范围广泛的向量计算。
|
||||
|
||||
这是对数组元素的简单标量计算:
|
||||
|
||||
```java
|
||||
void scalarComputation(float[] a, float[] b, float[] c) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这是使用 Vector API 进行的等效向量计算:
|
||||
|
||||
```java
|
||||
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
|
||||
|
||||
void vectorComputation(float[] a, float[] b, float[] c) {
|
||||
int i = 0;
|
||||
int upperBound = SPECIES.loopBound(a.length);
|
||||
for (; i < upperBound; i += SPECIES.length()) {
|
||||
// FloatVector va, vb, vc;
|
||||
var va = FloatVector.fromArray(SPECIES, a, i);
|
||||
var vb = FloatVector.fromArray(SPECIES, b, i);
|
||||
var vc = va.mul(va)
|
||||
.add(vb.mul(vb))
|
||||
.neg();
|
||||
vc.intoArray(c, i);
|
||||
}
|
||||
for (; i < a.length; i++) {
|
||||
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
在 JDK 18 中,向量 API 的性能得到了进一步的优化。
|
||||
|
||||
## JEP 418:互联网地址解析 SPI
|
||||
|
||||
Java 18 定义了一个全新的 SPI(service-provider interface),用于主要名称和地址的解析,以便 `java.net.InetAddress` 可以使用平台之外的第三方解析器。
|
||||
|
||||
## JEP 419:Foreign Function & Memory API(第二次孵化)
|
||||
|
||||
Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。
|
||||
|
||||
外部函数和内存 API 在 Java 17 中进行了第一轮孵化,由 [JEP 412](https://openjdk.java.net/jeps/412) 提出。第二轮孵化由[ JEP 419](https://openjdk.org/jeps/419) 提出并集成到了 Java 18 中,预览由 [JEP 424](https://openjdk.org/jeps/424) 提出并集成到了 Java 19 中。
|
||||
|
||||
在 [Java 19 新特性概览](./java19.md) 中,我有详细介绍到外部函数和内存 API,这里就不再做额外的介绍了。
|
||||
Java 18 定义了一个全新的 SPI(service-provider interface),用于主要名称和地址的解析,以便 `java.net.InetAddress` 可以使用平台之外的第三方解析器。
|
@ -25,7 +25,7 @@ JDK 19 只有 7 个新特性:
|
||||
|
||||
Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。
|
||||
|
||||
外部函数和内存 API 在 Java 17 中进行了第一轮孵化,由 [JEP 412](https://openjdk.java.net/jeps/412) 提出。第二轮孵化由[ JEP 419](https://openjdk.org/jeps/419) 提出并集成到了 Java 18 中,预览由 [JEP 424](https://openjdk.org/jeps/424) 提出并集成到了 Java 19 中。
|
||||
外部函数和内存 API 之前在 JDK 17 中孵化,在 JDK 18 中重新孵化。
|
||||
|
||||
在没有外部函数和内存 API 之前:
|
||||
|
||||
@ -84,9 +84,45 @@ Java 虚拟线程的详细解读可以看这篇文章:[Java19 正式 GA!看
|
||||
|
||||
## JEP 426: 向量 API(第四次孵化)
|
||||
|
||||
向量(Vector) API 最初由 [JEP 338](https://openjdk.java.net/jeps/338) 提出,并作为[孵化 API](http://openjdk.java.net/jeps/11)集成到 Java 16 中。第二轮孵化由 [JEP 414](https://openjdk.java.net/jeps/414) 提出并集成到 Java 17 中,第三轮孵化由 [JEP 417](https://openjdk.java.net/jeps/417) 提出并集成到 Java 18 中,第四轮由 [JEP 426](https://openjdk.java.net/jeps/426) 提出并集成到了 Java 19 中。
|
||||
向量(Vector) API 最初由[JEP 338](https://openjdk.java.net/jeps/338)提出,并作为[孵化 API](http://openjdk.java.net/jeps/11)集成到 JDK 16 中。第二轮孵化由[JEP 414](https://openjdk.java.net/jeps/414)提出并集成到 JDK 17 中。第三轮孵化由[JEP 417](https://openjdk.java.net/jeps/417)提出并集成到 JDK 18 中。
|
||||
|
||||
在 [Java 18 新特性概览](./java18.md) 中,我有详细介绍到向量 API,这里就不再做额外的介绍了。
|
||||
向量计算由对向量的一系列操作组成。向量 API 用来表达向量计算,该计算可以在运行时可靠地编译为支持的 CPU 架构上的最佳向量指令,从而实现优于等效标量计算的性能。
|
||||
|
||||
向量 API 的目标是为用户提供简洁易用且与平台无关的表达范围广泛的向量计算。
|
||||
|
||||
这是对数组元素的简单标量计算:
|
||||
|
||||
```java
|
||||
void scalarComputation(float[] a, float[] b, float[] c) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这是使用 Vector API 进行的等效向量计算:
|
||||
|
||||
```java
|
||||
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
|
||||
|
||||
void vectorComputation(float[] a, float[] b, float[] c) {
|
||||
int i = 0;
|
||||
int upperBound = SPECIES.loopBound(a.length);
|
||||
for (; i < upperBound; i += SPECIES.length()) {
|
||||
// FloatVector va, vb, vc;
|
||||
var va = FloatVector.fromArray(SPECIES, a, i);
|
||||
var vb = FloatVector.fromArray(SPECIES, b, i);
|
||||
var vc = va.mul(va)
|
||||
.add(vb.mul(vb))
|
||||
.neg();
|
||||
vc.intoArray(c, i);
|
||||
}
|
||||
for (; i < a.length; i++) {
|
||||
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## JEP 428: 结构化并发(孵化)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user