Java 18 新功能介绍
文章持续更新,可以关注公众号程序猿阿朗或访问未读代码博客。
本文 Github.com/niumoo/JavaNotes 已经收录,欢迎Star。
Java 18 在2022 年 3 月 22 日正式发布,Java 18 不是一个长期支持版本,这次更新共带来 9 个新功能。
OpenJDK Java 18 下载:https://jdk.java.net/18/
OpenJDK Java 18 文档:https://openjdk.java.net/projects/jdk/18/
| JEP | 描述 |
|---|---|
| JEP 400 | 默认为 UTF-8 |
| JEP 408 | 简单的网络服务器 |
| JEP 413 | Java API 文档中的代码片段 |
| JEP 416 | 使用方法句柄重新实现核心反射 |
| JEP 417 | Vector API(三次孵化) |
| JEP 418 | 互联网地址解析 SPI |
| JEP 419 | Foreign Function & Memory API (二次孵化) |
| JEP 420 | switch 模式匹配(二次预览) |
| JEP 421 | 弃用完成删除 |
JEP 400:默认 UTF-8 字符编码
JDK 一直都是支持 UTF-8 字符编码,这次是把 UTF-8 设置为了默认编码,也就是在不加任何指定的情况下,默认所有需要用到编码的 JDK API 都使用 UTF-8 编码,这样就可以避免因为不同系统,不同地区,不同环境之间产生的编码问题。
Mac OS 默认使用 UTF-8 作为默认编码,但是其他操作系统上,编码可能取决于系统的配置或者所在区域的设置。如中国大陆的 windows 使用 GBK 作为默认编码。很多同学初学 Java 时可能都遇到过一个正常编写 Java 类,在 windows 系统的命令控制台中运行却出现乱码的情况。
使用下面的命令可以输出 JDK 的当前编码。
# Mac 系统,默认 UTF-8
➜ ~ java -XshowSettings:properties -version 2>&1 | grep file.encoding
file.encoding = UTF-8
file.encoding.pkg = sun.io
➜ ~
下面编写一个简单的 Java 程序,输出默认字符编码,然后输出中文汉字 ”你好“,看看 Java 18 和 Java 17 运行区别。
系统环境:Windows 11
import java.nio.charset.Charset;
public class Hello{
public static void main(String[] args) {
System.out.println(Charset.defaultCharset()); System.out.println("你好"); }
}
从下面的运行结果中可以看到,使用 JDK 17 运行输出的默认字符编码是 GBK,输出的中文 ”你好“ 已经乱码了;乱码是因为 VsCode 默认的文本编辑器编码是 UTF-8,而中国地区的 Windows 11 默认字符编码是 GBK,也是 JDK 17 默认获取到的编码,所以会在控制台输出时乱码;而使用 JDK 18 输出的默认编码就是 UTF-8,所以可以正常的输出中文 ”你好“。

JEP 408:简单的 Web服务器
在 Java 18 中,提供了一个新命令 jwebserver,运行这个命令可以启动一个简单的 、最小化的静态Web 服务器,它不支持 CGI 和 Servlet,所以最好的使用场景是用来测试、教育、演示等需求。
其实在如 Python、Ruby、PHP、Erlang 等许多平台都提供了开箱即用的 Web 服务器,可见一个简单的Web 服务器是一个常见的需求,Java 一直没有这方面的支持,现在可以了。
在 Java 18 中,使用 jwebserver 启动一个 Web 服务器,默认发布的是当前目录。
在当前目录创建一个网页文件 index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1>标题</h1>
</body>
</html>
启动 jwebserver.
➜ bin ./jwebserver
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /Users/darcy/develop/jdk-18.jdk/Contents/Home/bin and subdirectories on 127.0.0.1 port 8000
URL http://127.0.0.1:8000/
浏览器访问:

有请求时会在控制台输出请求信息:
127.0.0.1 - - [26/3月/2022:16:53:30 +0800] "GET /favicon.ico HTTP/1.1" 404 -
127.0.0.1 - - [26/3月/2022:16:55:13 +0800] "GET / HTTP/1.1" 200 -
通过 help 参数可以查看 jwebserver 支持的参数。
➜ bin ./jwebserver --help
Usage: jwebserver [-b bind address] [-p port] [-d directory]
[-o none|info|verbose] [-h to show options]
[-version to show version information]
Options:
-b, --bind-address - 绑定地址. Default: 127.0.0.1 (loopback).
For all interfaces use "-b 0.0.0.0" or "-b ::".
-d, --directory - 指定目录. Default: current directory.
-o, --output - Output format. none|info|verbose. Default: info.
-p, --port - 绑定端口. Default: 8000.
-h, -?, --help - Prints this help message and exits.
-version, --version - Prints version information and exits.
To stop the server, press Ctrl + C.
JEP 413:Javadoc 中支持代码片段
在 Java 18 之前,已经支持在 Javadoc 中引入代码片段,这样可以在某些场景下更好的展示描述信息,但是之前的支持功能有限,比如我想高亮代码片段中的某一段代码是无能为力的。现在 Java 18 优化了这个问题,增加了 @snippet 来引入更高级的代码片段。
在 Java 18 之前,使用 <pre>{@code ...}</pre> 来引入代码片段。
/**
* 时间工具类
* Java 18 之前引入代码片段:
* <pre>{@code
* public static String timeStamp() {
* long time = System.currentTimeMillis();
* return String.valueOf(time / 1000);
* }
* }</pre>
*
*/
生成 Javadoc 之后,效果如下:

高亮代码片段
从 Java 18 开始,可以使用 @snippet 来生成注释,且可以高亮某个代码片段。
/**
* 在 Java 18 之后可以使用新的方式
* 下面的代码演示如何使用 {@code Optional.isPresent}:
* {@snippet :
* if (v.isPresent()) {
* System.out.println("v: " + v.get());
* }
* }
*
* 高亮显示 println
*
* {@snippet :
* class HelloWorld {
* public static void main(String... args) {
* System.out.println("Hello World!"); // @highlight substring="println"
* }
* }
* }
*
*/
效果如下,更直观,效果更好。

正则高亮代码片段
甚至可以使用正则来高亮某一段中的某些关键词:
/**
* 正则高亮:
* {@snippet :
* public static void main(String... args) {
* for (var arg : args) { // @highlight region regex = "\barg\b"
* if (!arg.isBlank()) {
* System.out.println(arg);
* }
* } // @end
* }
* }
*/
生成的 Javadoc 效果如下:

替换代码片段
可以使用正则表达式来替换某一段代码。
/**
* 正则替换:
* {@snippet :
* class HelloWorld {
* public static void main(String... args) {
* System.out.println("Hello World!"); // @replace regex='".*"' replacement="..."
* }
* }
* }
*/
这段注释会生成如下 Javadoc 效果。
class HelloWorld {
public static void main(String... args) {
System.out.println(...);
}
}
附:Javadoc 生成方式
# 使用 javadoc 命令生成 Javadoc 文档
➜ bin ./javadoc -public -sourcepath ./src -subpackages com -encoding utf-8 -charset utf-8 -d ./javadocout
# 使用 Java 18 的 jwebserver 把生成的 Javadoc 发布测试
➜ bin ./jwebserver -d /Users/darcy/develop/javadocout
访问测试:

JEP 416:使用方法句柄重新实现反射核心功能
Java 18 改进了 java.lang.reflect.Method、Constructor 的实现逻辑,使之性能更好,速度更快。这项改动不会改动相关 API ,这意味着开发中不需要改动反射相关代码,就可以体验到性能更好反射。
OpenJDK 官方给出了新老实现的反射性能基准测试结果。
Java 18 之前:
Benchmark Mode Cnt Score Error Units
ReflectionSpeedBenchmark.constructorConst avgt 10 68.049 ± 0.872 ns/opReflectionSpeedBenchmark.constructorPoly avgt 10 94.132 ± 1.805 ns/op
ReflectionSpeedBenchmark.constructorVar avgt 10 64.543 ± 0.799 ns/op
ReflectionSpeedBenchmark.instanceFieldConst avgt 10 35.361 ± 0.492 ns/opReflectionSpeedBenchmark.instanceFieldPoly avgt 10 67.089 ± 3.288 ns/op
ReflectionSpeedBenchmark.instanceFieldVar avgt 10 35.745 ± 0.554 ns/op
ReflectionSpeedBenchmark.instanceMethodConst avgt 10 77.925 ± 2.026 ns/op
ReflectionSpeedBenchmark.instanceMethodPoly avgt 10 96.094 ± 2.269 ns/op
ReflectionSpeedBenchmark.instanceMethodVar avgt 10 80.002 ± 4.267 ns/op
ReflectionSpeedBenchmark.staticFieldConst avgt 10 33.442 ± 2.659 ns/op
ReflectionSpeedBenchmark.staticFieldPoly avgt 10 51.918 ± 1.522 ns/op
ReflectionSpeedBenchmark.staticFieldVar avgt 10 33.967 ± 0.451 ns/op
ReflectionSpeedBenchmark.staticMethodConst avgt 10 75.380 ± 1.660 ns/op
ReflectionSpeedBenchmark.staticMethodPoly avgt 10 93.553 ± 1.037 ns/op
ReflectionSpeedBenchmark.staticMethodVar avgt 10 76.728 ± 1.614 ns/op
Java 18 的新实现:
Benchmark Mode Cnt Score Error Units
ReflectionSpeedBenchmark.constructorConst avgt 10 32.392 ± 0.473 ns/opReflectionSpeedBenchmark.constructorPoly avgt 10 113.947 ± 1.205 ns/op
ReflectionSpeedBenchmark.constructorVar avgt 10 76.885 ± 1.128 ns/op
ReflectionSpeedBenchmark.instanceFieldConst avgt 10 18.569 ± 0.161 ns/opReflectionSpeedBenchmark.instanceFieldPoly avgt 10 98.671 ± 2.015 ns/op
ReflectionSpeedBenchmark.instanceFieldVar avgt 10 54.193 ± 3.510 ns/op
ReflectionSpeedBenchmark.instanceMethodConst avgt 10 33.421 ± 0.406 ns/op
ReflectionSpeedBenchmark.instanceMethodPoly avgt 10 109.129 ± 1.959 ns/op
ReflectionSpeedBenchmark.instanceMethodVar avgt 10 90.420 ± 2.187 ns/op
ReflectionSpeedBenchmark.staticFieldConst avgt 10 19.080 ± 0.179 ns/op
ReflectionSpeedBenchmark.staticFieldPoly avgt 10 92.130 ± 2.729 ns/op
ReflectionSpeedBenchmark.staticFieldVar avgt 10 53.899 ± 1.051 ns/op
ReflectionSpeedBenchmark.staticMethodConst avgt 10 35.907 ± 0.456 ns/op
ReflectionSpeedBenchmark.staticMethodPoly avgt 10 102.895 ± 1.604 ns/op
ReflectionSpeedBenchmark.staticMethodVar avgt 10 82.123 ± 0.629 ns/op
可以看到在某些场景下性能稍微好些。
JEP 417:Vector API(三次孵化)
在 Java 16 中引入一个新的 API 来进行向量计算,它可以在运行时可靠的编译为支持的 CPU 架构,从而实现更优的计算能力。
在 Java 17 中改进了 Vector API 性能,增强了例如对字符的操作、字节向量与布尔数组之间的相互转换等功能。
现在在 JDK 18 中将继续优化其性能。
JEP 418:互联网地址解析 SPI
对于互联网地址解析 SPI,为主机地址和域名地址解析定义一个 SPI,以便java.net.InetAddress可以使用平台内置解析器以外的解析器。
InetAddress inetAddress = InetAddress.getByName("www.wdbyte.com");
System.out.println(inetAddress.getHostAddress());
// 输出
// 106.14.229.49
JEP 419:Foreign Function & Memory API (第二次孵化)
新的 API 允许 Java 开发者与 JVM 之外的代码和数据进行交互,通过调用外部函数,可以在不使用 JNI 的情况下调用本地库。
这是一个孵化功能;需要添加--add-modules jdk.incubator.foreign来编译和运行 Java 代码,Java 18 改进了相关 API ,使之更加简单易用。
历史
- Java 14 JEP 370 (opens new window)引入了外部内存访问 API(孵化器)。
- Java 15 JEP 383 (opens new window)引入了外部内存访问 API(第二孵化器)。
- Java 16 JEP 389 (opens new window)引入了外部链接器 API(孵化器)。
- Java 16 JEP 393 (opens new window)引入了外部内存访问 API(第三孵化器)。
- Java 17 JEP 412 (opens new window)引入了外部函数和内存 API(孵化器)。
JEP 420:switch 表达式(二次孵化)
从 Java 17 开始,对于 Switch 的改进就已经在进行了,Java 17 的 JEP 406 已经对 Switch 表达式进行了增强,使之可以减少代码量。
下面是几个例子:
// JDK 17 以前
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;
}
而在 Java 17 之后,可以通过下面的写法进行改进:
// JDK 17 之后
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();
};
}
switch 可以和 null 进行结合判断:
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");
}
}
case 时可以加入复杂表达式:
static void testTriangle(Shape s) {
switch (s) {
case Triangle t && (t.calculateArea() > 100) -> System.out.println("Large triangle");
default ->
System.out.println("A shape, possibly a small triangle");
}
}
case 时可以进行类型判断:
sealed interface S permits A, B, C {}
final class A implements S {}
final class B implements S {}
record C(int i) implements S {} // Implicitly final
static int testSealedExhaustive(S s) {
return switch (s) {
case A a -> 1;
case B b -> 2;
case C c -> 3;
};
}
JEP 421:弃用删除相关
在未来将删除 Finalization,目前 Finalization 仍默认保持启用状态,但是已经可以手动禁用;在未来的版本中,将会默认禁用;在以后的版本中,它将被删除。需要进行资源管理可以尝试 try-with-resources 或者 java.lang.ref.Cleaner。
参考
订阅
可以微信搜一搜程序猿阿朗或访问未读代码博客阅读。
本文 Github.com/niumoo/JavaNotes 已经收录,欢迎Star。
Java 18 新功能介绍的更多相关文章
- Java 19 新功能介绍
点赞再看,动力无限. 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Java 19 在2022 年 9 ...
- Java 14 新功能介绍
不做标题党,认认真真写个文章. 文章已经收录在 Github.com/niumoo/JavaNotes 和未读代码博客,点关注,不迷路. Java 14 早在 2019 年 9 月就已经发布,虽然不是 ...
- 超详细 Java 15 新功能介绍
点赞再看,动力无限.微信搜「程序猿阿朗 」,认认真真写文章. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Java 15 在 2 ...
- Java 17 新功能介绍(LTS)
点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Jav ...
- Java 16 新功能介绍
点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 程序猿阿朗博客 已经收录,有很多知识点和系列文章. Ja ...
- CentOS以及Oracle数据库发展历史及各版本新功能介绍, 便于构造环境时有个对应关系
CentOS版本历史 版本 CentOS版本号有两个部分,一个主要版本和一个次要版本,主要和次要版本号分别对应于RHEL的主要版本与更新包,CentOS采取从RHEL的源代码包来构建.例如CentOS ...
- 【Linux】Ubuntu18.04镜像下载,新功能介绍
一.Ubuntu18.04镜像下载 官方下载地址:http://releases.ubuntu.com/18.04/ 官方64位iso下载地址:http://releases.ubuntu.com/1 ...
- Java 11 新特性介绍
Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个 ...
- Java 12 新特性介绍,快来补一补
Java 12 早在 2019 年 3 月 19 日发布,它不是一个长久支持(LTS)版本.在这之前我们已经介绍过其他版本的新特性,如果需要可以点击下面的链接进行阅读. Java 11 新特性介绍 J ...
随机推荐
- 九鼎RK3399笔记一:Linux平台手册
@ 目录 一.git下载九鼎SDK 二.安装所需的软件包: 三.安装 kernel 及 u-boot 编译需要依赖的软件包 四.安装文件系统需要依赖的软件包 五.安装 Buildroot 编译需要依赖 ...
- Centos,Xshell和一些简单命令练习
先连接Xshell: 在虚拟机中查看IP,使用命令 ip addr: 然后在Xshell上, ssh 用户@虚拟机ip ,当前是 ssh root@192.168.13.235 : 如果想要 ...
- 类型转换Java day8
类型转换自动类型转换 从同种类型的低字节类型值直接转换到高类型字节值的转换可自动转换 类型自动转换示例 byte a = 20; int b = a;//不报错可正常转换 有些类型它在计算时默认以指定 ...
- MYSQL5.7详细安装步骤
0.更换yum源 1.打开 mirrors.aliyun.com,选择centos的系统,点击帮助 2.执行命令:yum install wget -y 3.改变某些文件的名称 mv /etc/yum ...
- bzoj5315/luoguP4517 [JSOI2018]防御网络(仙人掌,dp)
bzoj5315/luoguP4517 防御网络(仙人掌,dp) bzoj Luogu 题目描述略(太长了) 题解时间 本题和斯坦纳树无关. 题面保证了是一个仙人掌...? 但这个环之间甚至交点都没有 ...
- 半吊子菜鸟学Web开发4 --Html css学习2
1<a>标签,链接到另一个页面 <a href="目标网址" title="鼠标滑过显示的文本">链接显示的文本</a> H ...
- switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?
答:在Java 5以前,switch(expr)中,expr只能是byte.short.char.int.从Java 5开始,Java中引入了枚举类型,expr也可以是enum类型,从Java 7开始 ...
- Mycat新增数据报错can't fetch sequnce in db,sequnce
Mycat报错 2021-11-08 17:13:01,310 [ERROR][Thread-1] MyCATSequenceProcessor.executeSeq(SesionSQLPair) j ...
- char 和 varchar 的区别是什么?float 和 double 的区别是什么?
char 和 varchar 的区别是什么? char(n) :固定长度类型,比如订阅 char(10),当你输入"abc"三个字符的时候,它们占的空间还是 10 个字节,其他 7 ...
- ApplicationContext 通常的实现是什么?
FileSystemXmlApplicationContext :此容器从一个 XML 文件中加 载 beans 的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数. ClassPat ...