编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

保姆级升级 java17 指南,建议收藏

gowuye 2024-04-03 16:15 15 浏览 0 评论

一、前言

Java 17,一个长期支持 (LTS) 版本已经发布半个多月。 不幸的是,许多应用程序仍在旧版本的 Java 上运行,例如以前的 LTS 版本:Java 8 和 Java 11。本文解释了你应该升级应用程序的原因,并帮助你实际升级到 Java 17。

但首先,许多人都可能会问:“为什么要升级?”

  • java9 紧凑字符串(更加节省内存)
  • java11 httpclient
  • java12 switch 表达式(简化代码)
  • java13 多行文本
  • java14 record,匹配模式(简化代码)
  • 等等...

随着 Java 版本迭代,GC 得到大量优化,相对于老版本更快并且节省内存。仅仅靠升级 Java 版本就可以为我们带来众多收益。


二、在 Java 升级期间需要更改什么?

你的应用程序包含你和你的团队编写的代码,并且可能还包含依赖项。 如果从 JDK 中删除了某些内容,则可能会破坏代码、依赖项或两者。 通常有助于确保这些依赖项是最新的,以解决这些问题。 有时,你可能需要等到框架发布与最新 Java 版本兼容的新版本,然后才能开始升级过程。 这意味着作为升级前评估过程的一部分,你对你使用的依赖项需要有很好的了解。

大多数功能不会一次性从 JDK 中全部删除。 首先,功能被标记为弃用。 例如,用于 XML 绑定的 Java 架构 (JAXB) 在 Java 9 中被标记为弃用,然后在 Java 11 中才被删除。如果你一直在更新,那么你会知道弃用,并且你可以在功能被删除之前解决这些问题。 但是,如果你直接从 Java 8 跳到 Java 17,那么可能会踩到很多坑。

要查看 API 更改,例如,查看特定 Java 版本中哪些方法被删除或添加到 String API 中,请查看 Marc Hoffmann 和 Cay Horstmann 撰写的 The Java Version Almanac。


三、多版本 JAR 功能

如果你的基础组件任然被使用在旧的 JDK并且在他们的站点上升级不受你的控制怎么办? Java 9 和 JEP 238 中引入的多版本 JAR 功能可能很有用,因为它允许你将多个 Java 版本(包括早于 Java 9 的版本)的代码打包在一个 JAR 文件中。

例如:创建一个 Application 类(清单 1)和一个 Student 类(清单 2)并将它们放在文件夹 src/main/java/com/example 中,Student 类在 Java 8 上运行。

清单 1. Application class

public class Application {

   public static void main(String[] args) {
       Student student = new Student("James ");
       System.out.println("Implementation " + student.implementation());
       System.out.println("Student name James contains a blank: " + student.isBlankName());
   }
}

清单 2. Student class for Java 8

public class Student {
   final private String firstName;

   public Student(String firstName) {
       this.firstName = firstName;
   }

   boolean isBlankName() {
       return firstName == null || firstName.trim().isEmpty();
   }

   static String implementation() { return "class"; }
}

接下来,创建一个 Student record(清单 3),它不仅使用了 record(Java 14 中引入)而且还使用了 String.isBlank() 方法(Java 11 中引入),并将其放在 src/main/java17/com/example 文件夹。

清单 3. 使用新语法的 Student record

public record Student(String firstName) {
   boolean isBlankName() {
       return firstName.isBlank();
   }

   static String implementation() { return "record"; }
}

根据你使用的构建工具,需要一些配置。 Maven 示例可以在我的 GitHub repository 中找到。 该示例基于 Java 17 构建并创建 JAR 文件。 在 JDK 17 或更高版本上执行 JAR 文件时,将使用学生记录。 在旧版本上执行 JAR 文件时,将使用 Student 类。

当然你也可以参考 https://github.com/xkcoding/simple-http(译者注),我给它 pr 了 java11 下的 HttpClient 支持,该工具使用 Java8 编译。

此功能非常有用,例如,如果新 API 提供更好的性能,因为你可以为拥有最新 Java 版本的客户使用这些 API。 相同的 JAR 文件可用于使用较旧 JDK 的客户,而不会提高性能。

请注意,所有实现(在本例中为 Student)都应具有相同的公共 API 以防止运行时问题。 不幸的是,构建工具不会验证公共 API,但一些 IDE 会验证。 另外,在 JDK 17 中,你可以使用 jar –validate 命令来验证 JAR 文件。

需要注意的是某些版本的 JDK 中存在预览功能。 一些更大的特性首先作为预览发布,并且可能会在下一个 JDK 之一中产生最终特性。 这些预览功能同时存在于 Java 的 LTS 和非 LTS 版本中。 这些功能使用 enable-preview标志启用,默认情况下关闭。 如果你在生产代码中使用这些预览功能,请注意它们可能会在 JDK 版本之间发生变化,这可能会导致需要将代码进行一些调试或重构。


四、有关 Java 弃用和删除的功能

在升级 JDK 之前,请确保你的 IDE、构建工具和依赖项是最新的。Maven Versions Plugin 和 Gradle Versions Plugin 显示你拥有哪些依赖项并列出最新的可用版本。

请注意,这些工具仅显示你使用的依赖的新版本——但有时依赖的名称会发生变化、分叉或代码移动。 例如:JAXB 最初是通过 javax.xml.bind:jaxb-api 提供的,但在它过渡到 Eclipse Foundation 后更改为 jakarta.xml.bind:jakarta.xml.bind-api。 要查找此类更改,你可以使用 Jonathan Lermitage 的 Old GroupIds Alerter plugin for Maven 或他的 plugin for Gradle。

JavaFX. 从 Java 11 开始,不再包含 JavaFX 作为规范的一部分,并且大多数 JDK 版本已将其删除。 你可以使用来自 Gluon 的单独构建的 JavaFX 或将 OpenJFX 依赖项添加到你的项目。

Fonts. 曾几何时,JDK 包含一些字体,但从 Java 11 开始,它们被删除了。 例如:如果你使用 Apache POI(Microsoft Office 兼容文档的 Java API),你将需要字体。 操作系统需要提供字体,因为它们不再存在于 JDK 中。 但是,在 Alpine Linux 等操作系统上,必须使用 apt install fontconfig 命令手动安装字体。 根据你使用的字体,可能需要额外的包。

Java Mission Control. 这是一个非常有用的工具,用于监视和分析你的应用程序。 强烈建议你了解一下。 Java Mission Control 曾经包含在 JDK 中,但现在改了名并且需要单独下载:JDK Mission Control。

Java EE. JDK 11 中最大的变化是删除了 Java EE 模块。 许多应用程序都依赖 Java EE 模块,例如:前面提到的 JAXB。 由于这些模块不再存在于 JDK 中,因此你需要添加相关的依赖项。表格 1 列出了各种模块及其依赖项。 请注意,JAXB 和 JAX-WS 都需要两个依赖项:一个用于 API,另一个用于实现。 另一个变化是命名约定,因为 Java EE 由 Eclipse 基金会以 Jakarta EE 的名义进行维护。 你的包导入可能需要调整,较新版本的 Jakarta EE 使用 jakarta.xml.bind.* 而不是 javax.xml.bind.*。

表格 1. Java EE 模块和当前的替代品

CORBA. Java 的 CORBA 模块没有官方替代品,该模块在 Java 11 中被删除。但是 Oracle GlassFish Server 包含了 CORBA 的实现。

Nashorn. Java 15 删除了 Nashorn JavaScript 引擎。 如果仍想使用它,你可以添加 nashorn-core 依赖。

<dependency>
    <groupId>org.openjdk.nashorn</groupId>
    <artifactId>nashorn-core</artifactId>
    <version>15.3</version>
</dependency>

Experimental compilers. Java 17 删除了对 GraalVM 的实验性提前 (AOT) 和即时 (JIT) 编译器的支持,详见 JEP 410。


五、寻找不受支持的文件

你可能会遇到 Unsupported class file major version 61 这样的错误。我已经在 JaCoCo 代码覆盖库和各种其他 Maven 插件中看到了它。 消息中版本 61 指的是 Java 17。因此,在这种情况下,这意味着你使用的框架或工具的版本不支持 Java 17。因此,你应该将框架或工具升级到 新版本。


六、JDK 内部 API

Java 16 和 Java 17 封装了 JDK 内部 API,这会影响 Lombok 等各种框架。 你可能会看到诸如 module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module,这意味着你的应用程序无法再访问 JDK 的这些内部 API。

通常,我建议升级所有使用这些内部结构的依赖项,并确保你自己的代码不再使用 JDK 的内部 API。

如果这是不可能的,有一个变通方法仍然使你的应用程序能够访问内部。 例如,如果你需要访问 comp 模块,请使用以下命令:

--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED

但是,这只是解决问题的最后手段,最好还是停止使用这些内部 API,因为你正在绕过 Java 团队添加的重要保护措施。

关于此问题更多详细信息可查看 Java 16 的 JEP 396 和 Java 17 的 JEP 403。


七、结论

升级依赖项和为 JDK 已经删除的功能找到替代方案就可以避免大部问题。 我推荐一种结构化的方法来逐步升级:首先,确保代码可以编译,然后运行测试,然后运行应用程序。

如果你可以告诉自己、你的团队和你的公司,你可以在 JDK 17 上编译和测试所有内容,而不必告诉他们几乎已经完成,或者更糟糕的是,它只完成了 80%,那么迁移过程就会好得多。

我希望这篇文章能够对你有所作用,能帮助你平稳升级到 Java17。


八、译者说

笔者开源的微服务组件 mica 已经适配 java17,mybatis-plus 新版也已经支持。目前笔者已经有一部分服务升级到 Java17,很丝滑,如果你有升级 Java 的想法,不妨直接升级到 Java17。关注我,学习技术不迷路!

相关推荐

嵌入式C语言中常量的应用实例(嵌入式c语言中常量的应用实例是什么)

常量,我们都知道,就是数值保持不变的量。在C语言中,常量一旦初始化了,它的值将在整个程序运行周期内,不允许发生任何变化。常量与变量是相对的,我们实际项目中经常会用到它。定义常量的两种方式C语言中主要有...

C语言编程基础知识汇总学习,适合初学者!更新常量知识

(二)整型常量整型常量有3种形式:十进制整型常量、八进制整型常量和十六进制整型常量。(注意:c语言中没有直接表示二进制的整型常量,在c语言源程序中不会出现二进制。)书写方式如下:十进制整型常量:123...

【C语言】第二章第六节:字符串常量

第二章第六节:字符串常量。下表C语言中的常用转义字符。·字符形式功能:ASCIl码(十进制形式)。→\t水平制表(横向跳格:跳到下一个tab位置)。→\b退格8。→\r回车(不换行,光标移到本行行首)...

「GCTT 出品」Go 系列教程——5. 常量

这是我们Golang系列教程的第五篇。定义在Go语言中,术语”常量”用于表示固定的值。比如5、-89、IloveGo、67.89等等。看看下面的代码:varaint=50v...

每日C语言-常量指针、指针常量、指向常量的指针常量

一、常量指针1)什么是常量指针?通过该指针不可以修改其所指向存储单元中的值指针本身即地址可以被修改2)定义:类型说明符const*指针变量;类型说明符表示指针所指向存储单元中的值得数据类型指针...

C语言-符号常量、常变量、变量之我见

更新内容:新增音频。音频和文章一起更配oHello,大家好,又和大家见面了~~相信很多朋友们听了C语言的“符号常量”、“常变量”、“变量”后还是对这三者一脸懵逼吧。不管老师怎么歇斯底里地讲解,同学们迷...

零基础带你学习C语言:四:探索常量与变量

前言常量与变量学习;一:分析:short、float、long类型#include<stdio.h>intmain(){shortage=18;floatweight=12...

C语言中是如何定义常量的?那定义字符串呢?

常量有整型常量、浮点型常量、字符型常量及字符串常量。‘常量定义是指定义符号常量,用一个标识符来代表一个常量,通过宏定义预处理指令来实现。常量的定义:#definecount60这就定义了一个常量...

C语言符号常量的优点,会是那几点?

符号常量是一个常量,是不变量,所以,在编译的时候,就把符号常量出现的地方,替换为符号常量对应的常量。符号常量一般用户定义一个全局使用的数据,而且要改变该数据的时候,只需要改变符号常量的值,代码中引用符...

嵌入式开发- C语言数据类型-常量(c语言嵌入式是干嘛的)

基本数据类型的常量-掌握**整型常量:**常量是指在程序运行期间其数值不发生变化的数据。整型常量通常简称为整数整数可以是十进制数、八进制数、十六进制数八进制06334十六进制0xd1...

c语言解剖课:只读变量、常量、字面量傻傻分不清?

写在前面本篇主题的缘起,是因为一个计算机专业的大学生在和我讨论c语言问题时,说const常量如何如何,我说变量被const修饰了,还是变量,不是“常量”。他给了我一个截图:他说大模型都是这样回答的,变...

C/C++编程笔记:C数组、字符串常量和指针!三分钟弄懂它

想弄懂C语言中数组和指针的关系吗?这篇文章就占据你三分钟时间,看完你肯定会有收获!数组数组声明为数据类型名称[constant-size],并将一个数据类型的一个或多个实例分组到一个可寻址的位...

C语言入门到精通【第008讲】——C语言常量

C语言常量常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。常量就像是常规的变量,只不过常...

这是C语言无法修改得东西,C语言基础教程之常量解析

常量是指程序在执行期间不会改变的固定值。这些固定值也称为文字。常量可以是任何基本数据类型,如整数常量,浮点常量,字符常量或字符串文字,还有枚举常量。常量被视为常规变量,除了它们的值在定义后无法修改。整...

C语言中的单精度、双精度、常量等都有什么意思?

刚接触C语言时,对于常量,变量,浮点,单精度,双精度等问题的理解,大都很模糊不清,其实在程序运行过程中,其值不能改变的量称为常量。如12、0、-3为整型常量,4.6、-1.23为实型常量,'a'、'...

取消回复欢迎 发表评论: