都要Java 20了你还在玩Java 8?
#01 Java版本演进
从第一个1995年发布的alpha和beta Java公开版本到即将发布的Java20, 已经有28个年头。这期间也发布了20多个版本,但其中被大家常用的也就几个版本,甚至现在好多应用还在用着Java8。
在我们选择jdk版本的时候,尽量选择LTS(长期支持)版本,LTS 版本被认为是最稳定的版本,它经历了广泛的测试,并且大多包含了多年积累的改进。需要注意的是,LTS 版本的软件不一定涉及功能更新,除非有一个更新的 LTS 版本。但是,你会在 LTS 版本的更新中得到必要的错误修复和安全修复。
Java 17, 11, 8 为目前提供支持的 LTS版本;Java 10 是上一个快速发布版本,且已不再被支持。2018年9月,随着 Java 11 的发布,Java 10 自当日起不再被支持。Oracle 将在 2019 年 1 月前为商业用途中的 Java 8 长期支持,而针对非商用的更新将继续提供,直至 2020 年 12 月;此外,AdoptOpenJDK 也为 Java 8 提供免费更新。针对 Java 11 的长期支持将不再由 Oracle 提供,而是改由 OpenJDK 社区提供,例如 Eclipse Adoptium(以前称之为 AdoptOpenJDK) 的 Eclipse Temurin。
#02 JDK 17 工具
Jdk中自带的工具可以给我们在代码开发和维护,性能调优等方面给予巨大的帮助,我们有必要了解一下jdk17中自带的一些开发运行工具。
2.1 所有平台
-
jar - 为类和资源创建存档,并从存档中操作或恢复单个类或资源
-
jarsigner - 签署并验证 Java 存档 (JAR) 文件
-
java - 启动 Java 应用程序
-
javac - 读取 Java 类和接口定义并将它们编译成字节码和类文件
-
javadoc - 从 Java 源文件生成 API 文档的 HTML 页面
-
javap - 反汇编一个或多个类文件
-
jcmd - 向正在运行的 Java 虚拟机 (JVM) 发送诊断命令请求
-
jconsole - 启动一个图形控制台来监视和管理 Java 应用程序
-
jdb - 查找和修复 Java 平台程序中的错误
-
jdeprscan - 扫描 jar 文件(或其他一些类文件的集合)以查找已弃用的 API 元素的静态分析工具
-
jdeps - 启动 Java 类依赖分析器
-
jfr - 解析和打印飞行记录器文件
-
jhsdb - 附加到 Java 进程或启动事后调试器以分析来自崩溃的 Java 虚拟机 (JVM) 的核心转储的内容
-
jinfo - 为指定的 Java 进程生成 Java 配置信息
-
jlink - 将一组模块及其依赖项组装并优化为自定义运行时映像
-
jmap - 打印指定进程的详细信息
-
jmod - 创建 JMOD 文件并列出现有 JMOD 文件的内容
-
jpackage - 打包一个独立的 Java 应用程序
-
jps - 列出目标系统上已检测的 JVM
-
jrunscript - 运行支持交互和批处理模式的命令行脚本外壳
-
jshell - 在读取-评估-打印循环 (REPL) 中交互式评估 Java 编程语言的声明、语句和表达式
-
jstack - 打印指定 Java 进程的 Java 线程的 Java 堆栈跟踪
-
jstat - 监控 JVM 统计信息
-
jstatd - 监控已检测的 Java HotSpot 虚拟机的创建和终止
-
keytool - 管理加密密钥、X.509 证书链和可信证书的密钥库(数据库)
-
rmid - 启动激活系统守护进程,使对象能够在 Java 虚拟机 (JVM) 中注册和激活
-
rmiregistry - 在当前主机的指定端口上创建并启动远程对象注册表
-
serialver - 以适合复制到进化类中的形式返回一个或多个类的“serialVersionUID”
2.2 仅适用于 Windows
-
jabswitch - 启用或禁用 Java Access Bridge
-
jaccessinspector - 使用 Java Accessibility Utilities API 检查有关 Java 虚拟机中对象的可访问信息
-
jaccesswalker - 浏览特定 Java 虚拟机中的组件树并在树视图中显示层次结构
-
javaw - 在没有控制台窗口的情况下启动 Java 应用程序
-
kinit - 获取并缓存 Kerberos 票证授予票证
-
klist - 显示本地凭证缓存和密钥表中的条目
-
ktab - 管理存储在本地密钥表中的主体名称和服务密钥
#03 从JDK8到JDK17的代码新特征
3.1 简洁的字符串函数
- isBlank():如果字符串为空或字符串仅包含空格(包括制表符),则返回 true。注意与isEmpty() 不同,isEmpty()仅在长度为 0 时返回 true。
- lines():将字符串拆分为字符串流,每个字符串包含一行。
- strip() :分别从开头和结尾;
- stripLeading()/stripTrailing()仅开始和仅结束删除空格。
- repeat(int times):返回一个字符串,该字符串采用原始字符串并按指定的次数重复该字符串。
- readString():允许从文件路径直接读取到字符串。
- writeString(Path path):将字符串直接写入指定路径处的文件。
- indent(int level):缩进字符串的指定量。负值只会影响前导空格。
- transform(Function f):将给定的 lambda 应用于字符串。
private void strFeatures() throws IOException {
//lines()方法示例,\n \r可以换行
String str = "Hello \njava17 \n!\r";
Stream<String> lines = str.lines();
lines.forEach(System.out::println);
//readString()方法示例
Path path = Path.of("D:\\good.txt");
String text = Files.readString(path).strip() ;
System.out.println(text);
}
3.2 字符串块
private void textBlocks() {
String textBlocks = """
{"name": "lisi",
"age": %d, "sex": "%s"}
""".formatted(12, "男");
System.out.println(textBlocks);
}
3.3 record更简洁的类定义
无需set/get方法和构造函数
record User2(String name, Integer age) {
@Override
public String toString() {
return "User2[" +
"name='" + name + '\'' +
", age=" + age +
']';
}
@Override
public boolean equals(Object obj) {
return false;
}
@Override
public int hashCode() {
return 0;
}
}
3.4 简单的switch表达式
private void newSwitch() {
int size = 3;
String cn = switch (size) {
case 1 -> "一";
case 2 -> "二";
case 3 -> "三";
default -> "未知";
};
System.out.println(cn);
}
3.5 密封类
/**
* 定义一个抽象密封类Vehicle ,它的实现类只能是Car , Bus这两个,
* 其他的实现类均不允许
*/
public abstract sealed class Vehicle permits Car, Bus {}
public final class Car extends Vehicle {
}
public final class Bus extends Vehicle{
}
3.6 Vector 向量计算
Vector 向量计算 API 是为了处理 SIMD(Single Instruction Multiple Data,单指令多数据)类型的操作,即并行执行的各种指令集。它利用支持向量指令的专用 CPU 硬件,并允许以管道的形式执行此类指令。这种运算方式可以让开发人员实现更高效的代码,充分利用底层硬件的潜力。日常使用包括科学代数线性应用程序、图像处理、字符处理、繁重的算术应用程序,以及任何需要对多个独立操作数应用一个运算的应用程序。 Vector 向量计算 API 是在 Java16 引入(参见 Java16 的新特性),可以在运行时借助 CPU 向量运算指令,实现更优的计算能力。在 Java17 中,针对性能和实现进行了改进,包括字节向量与布尔数组之间进行转换。
private void vectorCalc(){
final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
final float[] a = {1, 2, 3, 4};
final float[] b = {5, 6, 7, 8};
final float[] c = new float[3];
for (var i = 0; i < a.length; i += SPECIES.length()) {
var m = SPECIES.indexInRange(i, a.length);
var va = FloatVector.fromArray(SPECIES, a, i, m);
var vb = FloatVector.fromArray(SPECIES, b, i, m);
var vc = va.mul(vb);
vc.intoArray(c, i, m);
}
}