现代 Java 新特新
编辑前言
Java 8 自 2014 年 3 月18 日发布至今(2024), 这么多年过去了依然是国内使用最广泛的 JDK 版本, 正所谓 "他发任他发, 我用 Java 8", 突出一个稳字啊! 先来康一康 Java SE RoadMap:
Java 8 之后的10年里 Oracle 先后发布了13个版本, 其中3个 LTS 版本, 从里面的 Release 的功能可以看出来 Java 一直紧跟时代, 变化非常大, 总的来说就是迈向更轻(体积), 更快(性能), 更小(内存占用). 作为一个有灵魂码农, 也不能落后, 可以不用, 但不能不了解.
关于 Java 8 的介绍可以看我的老文章: Java8 Noob Tutorial
Java 9 - 11
Java 9
主要语言变化
新增
模块化系统(Module System): JSR 376
Project Jigsaw 的一部分
按需加载, 解决臃肿
module-info.java
通过
exports
,requires
关键字声明作用域(感觉像 nodejs?)
新版本定义机制:
$MAJOR.$MINOR.$SECURITY.$PATCH
更新
try-with-resources
语法允许变量使用 final 修饰, 语法升级diamond
语法允许匿名类(如果类型推断的参数类型可表示的话)接口允许定义
private
方法@SafeVarargs
允许声明在实例 private 方法上
主要 API 变化
引入
进程(Process): JEP 102, 全新 API
ProcessHandle
提供更好的管控操作系统内存(Memory): JEP 193,
VarHandle
作为正式 API 替代Unsafe
, 对变量执行原子和内存屏障操作日志(Logging): JEP 264, 全新日志 API 和服务
现在基本都用 Slf4j 了吧...
XML: JEP 268, 添加标准的 XML Catalog API
栈(Stack): JEP 259, 全新栈跟踪工具,
StackWalker
替代老的StackTraceElement
体系
更新
字符串(String): JEP 254, String 底层存储从
char[]
替换为byte[]
内存优化, 时间换空间
集合(Collections): JEP 269, 集合接口提供便利的工厂方法, 如,
Set.of(...)
并发(Concurrency): JEP 266,
CompletableFuture
以及其他并发组件提升Reactive Streams:
java.util.concurrent.Flow
编译器(Compiler): JEP 274, 提升
MethodHandle
通用性以及更好地编译优化MethodHandle
以及其他反射方式性能对比: Java Reflection, but Faster
注解(Annotation): JEP 277,
@Deprecated
注解增加since
和forRemoval
属性, 丰富 API 淘汰策略线程(Threading): JEP 285, 新增自选方法
Thread.onSpinWait
对象序列化(Serialization): JEP 290, 新增 API
ObjectInputFilter
过滤ObjectInputStream
XML: JEP 255, 更新 Xerces 2.11.0 解析 XML
Java Management Extensions (JMX): 支持远程诊断命令
脚本(Scripting):
国际化(Internationalization):
Java Database Connectivity (JDBC):
JDBC-ODBC 桥接移除
JDBC 4.2 升级
主要 JVM 变化
新增
更新
垃圾回收(Garbage Collection)
移除组合:
并发标记和清扫(Concurrent Mark Sweep Collector) CMS: JEP 291
DefNew + CMS
ParNew + SerialOld
Incremental CMS
Garbage-First(G1): JEP 248: Make G1 the Default Garbage Collector
提升可读性和性能优化
标记为默认 GC
统一 JVM 日志: JEP 158
输入/输出(I/O):
减少
<JDK_HOME>/jre/lib/charsets.ja
r 文件大小
性能提升(Performance)
java.lang.String
字节数组性能优化
工具(Tools)
Java 10
主要语言变化
新增
本地变量类型推断: JEP 286: Local-Variable Type Inference
用 var 来声明变量, 相关阅读: Java 10 新特性之局部变量类型推断
主要 API 变化
更新
通用: Optional 新增方法
orElseThrow()
方法来在没有值时抛出指定的异常
集合增强
List
,Set
,Map
提供了静态方法copyOf()
返回入参集合的一个不可变拷贝
java.util.stream.Collectors
中新增了静态方法, 用于将流中的元素收集为不可变的集合Collectors.toUnmodifiableList()
,Collectors.toUnmodifiableSet()
安全(Security):
JEP 319, 默认根证书
主要 JVM 变化
新增
JIT Compiler: JEP 317 实验性的 Java 编写的 JIT Compiler, Graal
更新
垃圾回收(Garbage Collection)
Garbage-First(G1): 并行 Full GC 支持
JEP 304: Garbage Collector Interface
内存(Memory): 运行 JVM Heap 在用户可选的设备上分配, 如: NV-DIMM
应用层级的 CDS: JEP 310: Application Class-Data Sharing
线程(Threading): JEP 312 Thread-Local Handshakes
工具(Tools)
javah: JEP 313 被移除
国际化(Internationalization): 增加 Unicode 语言 Tag 扩展
版本发布: JEP 322, 基于时间发布版本信息
Java 11(LTS)
主要语言变化
新增
字节码(Byte-code):
基于嵌套类型访问控制(JEP 181: Nest-Based Access Control)
新增常量池形式: CONSTANT_Dynamic(JEP 309: Dynamic Class-File Constants)
Lambda 参数局部变量语句: JEP 323: Local-Variable Syntax for Lambda Parameters
可以在 Lambda 表达式中使用 var
主要 API 变化
引入
HTTP: 新增 HTTP 客户端(JEP 321: HTTP Client (Standard))
更新
Optional 增强
新增了
isEmpty()
方法来判断指定的Optional
对象是否为空
String 增强
新增了
isBlank
,strip
,repeat
,lines
等方法
国际化(Internationalization):
Unicode 10 支持(JEP 327: Unicode 10)
安全(Security):
与 Curve25519 和 Curve448 的关键协议(JEP 324: Key Agreement with Curve25519 and Curve448)
Chacha20 和 Poly1305 加密算法(JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms)
TLS 1.3 支持(JEP 332: Transport Layer Security (TLS) 1.3)
移除 Java EE 和 CORBA 模块(JEP 320: Remove the Java EE and CORBA Modules)
java.xml.ws (JAX-WS, SAAJ and Web Services Metadata)
java.xml.bind (JAXB)
java.activation (JAF)
java.xml.ws.annotation (Common Annotations)
java.corba (CORBA)
java.transaction (JTA)
主要 JVM 变化
新增
JIT Compiler: JEP 317 实验性的 Java 编写的 JIT Compiler
垃圾回收(Garbage Collection)
工具
Java Fight Recorder(JEP 328: Flight Recorder)
java 命令直接启动单个 Java 源文件(JEP 330: Launch Single-File Source-Code Programs)
java helloword.java
类脚本, 无需预先编译, 直接运行, 比如写个简单的爬虫
低消耗 JVM Heap Profiling(JEP 331: Low-Overhead Heap Profiling)
更新
内存(Memory): 运行 JVM Heap 在用户可选的设备上分配, 如: NV-DIMM
应用层级的 CDS: JEP 310
Class-Data Sharing
工具(Tools)
不推荐 JavaScript 引擎 Nashorn(JEP 335: Deprecate the Nashorn JavaScript Engine)
不推荐 Pack200 工具(JEP 336: Deprecate the Pack200 Tools and API)
GUI:
移除 Java Applet
移除 Java Web Start
移除 JavaFX
指令: 提升 Aarch64 内联函数(JEP 315: Improve Aarch64 Intrinsics)
Java 12 - 17
Java 12
主要语言变化
新增
[预览] Switch 语句优化(JEP 325: Switch Expressions (Preview))
主要 API 变化
String
新增了indent
方法处理缩进Files
新增了mismatch
来对比两个文件NumberFormat
新增了对复杂的数字进行格式化的支持:getCompactNumberInstance
主要 JVM 变化
新增
单一 AArch64 端口(JEP 340: One AArch64 Port, Not Two)
默认 CDS 归档(JEP 341: Default CDS Archives)
垃圾回收(Garbage Collection)
[实验性] Shenandoah GC(JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental))
Microbenchmark 套件(JEP 230: Microbenchmark Suite)
更新
垃圾回收(Garbage Collection)
Garbage First(G1)
Java 13
主要语言变化
新增
[预览] Switch 语句优化更新(JEP 354: Switch Expressions (Preview))
新增
yield
关键字
[预览] 文件块(JEP 355: Text Blocks (Preview))
主要 API 变化
更新
网络(Network): 重新实现 Socket API(JEP 353: Reimplement the Legacy Socket API)
虚拟线程铺垫
主要 JVM 变化
更新
垃圾回收(Garbage Collection)
ZGC
返回未提交内存(JEP 351: ZGC: Uncommit Unused Memory)
Java 14
主要语言变化
新增
[预览] instanceof 语句优化(JEP 305: Pattern Matching for instanceof (Preview))
在
instanceof
块中转换变量
[预览] 文件块更新, 引入了两个新的转义字符 (JEP 368: Text Blocks (Second Preview))
\
: 表示行尾, 不引入换行符\s
: 表示单个空格
[预览] Record 类型(JEP 359: Records (Preview))
Immutable data
record Person(String name, Long id){}
Switch 语句优化(转正)(JEP 361: Switch Expressions (Standard))
主要 API 变化
引入
[孵化] 外部内存访问 API(JEP 370: Foreign-Memory Access API (Incubator))
主要 JVM 变化
更新
非 volatile 内存 ByteBuffer 映射(JEP 352: Non-Volatile Mapped Byte Buffers)
空指针异常内容辅助(JEP 358: Helpful NullPointerExceptions)
补充异常信息, 比如:
Cannot read field 'c' because 'a.b' is null.
垃圾回收(Garbage Collection)
ZGC
支持 macOS(JEP 364: ZGC on macOS)
支持 Windows(JEP 365: ZGC on Windows)
CMS
Garbage First(G1)
NUMA 架构内存分配(JEP 345: NUMA-Aware Memory Allocation for G1)
工具
JFR 流(JEP 349: JFR Event Streaming)
[孵化] 打包工具(JEP 343: Packaging Tool (Incubator))
移除 Pack200(JEP 367: Remove the Pack200 Tools and API)
Java 15
主要语言变化
引入
文本块(JEP 378: Text Blocks)
为框架(frameworks)所设计的, 隐藏类不能直接被其他类的字节码使用, 只能在运行时生成类并通过反射间接使用它们
更新
[预览] Sealed 类(JEP 360: Sealed Classes (Preview))
解决被
final
修饰的类不能被继承的尴尬
[预览] instanceof 语句优化(JEP 375: Pattern Matching for instanceof (Second Preview))
[预览] Record 类型(JEP 384: Records (Second Preview))
主要 API 变化
引入
[孵化] 外部内存访问 API(JEP 383: Foreign-Memory Access API (Second Incubator))
更新
网络(Network): 重新实现 Socket API(JEP 353: Reimplement the Legacy Socket API)
Remote Method Invocation(RMI): JEP 385: Deprecate RMI Activation for Removal
主要 JVM 变化
更新
移除 Solaris 和 SPARC JVM 实现(JEP 381: Remove the Solaris and SPARC Ports)
线程(Threading)
失效和不推荐使用偏向锁(JEP 374: Disable and Deprecate Biased Locking)
偏向锁的引入增加了 JVM 的复杂性大于其带来的性能提升
垃圾回收(Garbage Collection)
工具
移除 Nashorn JavaScript 引擎(JEP 372: Remove the Nashorn JavaScript Engine)
安全(Security):
Java 16
主要语言变化
引入
Record 类型正式引入(JEP 395: Records)
instanceof 语句优化正式引入(JEP 394: Pattern Matching for instanceof)
更新
Stream 新增
toList()
方法, 直接可转换成不可变的 Listlist.stream().toList()
模块化(Modular): JDK 内部 API 默认强封装(JEP 396: Strongly Encapsulate JDK Internals by Default)
[孵化] 向量 API(JEP 338: Vector API (Incubator))
API 将使开发人员能够轻松地用 Java 编写可移植的高性能向量算法
[预览] Sealed 类(JEP 397: Sealed Classes (Second Preview))
引入
网络(Network):
Unix-Domain Socket(JEP 380: Unix-Domain Socket Channels)
Native:
[孵化] 替代 JNI Java API: JEP 389: Foreign Linker API (Incubator)
[孵化] 外部内存访问 API(JEP 393: Foreign-Memory Access API (Third Incubator))
通用: 单个 API 应该能够对各种外部内存(如本机内存、持久内存、堆内存等)进行操作.
安全: 无论操作何种内存, API 都不应该破坏 JVM 的安全性.
控制: 可以自由的选择如何释放内存(显式、隐式等).
可用: 如果需要访问外部内存, API 应该是
sun.misc.Unsafe
.
主要 JVM 变化
引入
源码(SourceCode):
激活 C++ 14 特性(JEP 347: Enable C++14 Language Features)
迁移到 Git 上(JEP 357: Migrate from Mercurial to Git)
在此之前, OpenJDK 源代码是使用版本管理工具 Mercurial 进行管理, 现在迁移到了 Git
Alpine Linux 实现(JEP 386: Alpine Linux Port)
Windows/AArch64 实现(JEP 388: Windows/AArch64 Port)
更新
垃圾回收(Garbage Collection)
ZGC
工具(Tools)
jpackage 容器打包工具(JEP 392: Packaging Tool)
Java 17(LTS)
主要语言变化
引入
Sealed 类正式引入(JEP 409: Sealed Classes)
sealed
: 修饰类/接口, 用来描述这个类/接口为密封类/接口non-sealed
: 修饰类/接口, 用来描述这个类/接口为非密封类/接口permits
: 用在extends
和implements
之后, 指定可以继承或实现的类
浮点数: 浮点数默认
strictfp
(JEP 306: Restore Always-Strict Floating-Point Semantics)
更新
模块化(Modular): JDK 内部 API 强封装(JEP 403: Strongly Encapsulate JDK Internals)
[预览] Switch 语句增强模式匹配(JEP 406: Pattern Matching for switch (Preview))
类似
instanceof
的匹配+转换:case Integer i -> String.format("int %d", i);
[孵化] 向量 API(JEP 414: Vector API (Second Incubator))
主要 API 变化
引入
[孵化] 外部 Native 函数和内存 API(JEP 412: Foreign Function & Memory API (Incubator))
关联:
更新
工具(Utility): Random 增强(JEP 356: Enhanced Pseudo-Random Number Generators)
安全(Security):
不推荐 SecurityManager, 未来将移除(JEP 411: Deprecate the Security Manager for Removal)
Remote Method Invocation(RMI): 移除 RMI Activation(JEP 407: Remove RMI Activation)
对象序列化(Serialization): 上下文反序列化过滤器(JEP 415: Context-Specific Deserialization Filters)
用户界面(UI):
Applet: 不推荐使用, 未来移除(JEP 398: Deprecate the Applet API for Removal)
主要 JVM 变化
引入
源码(SourceCode):
macOS/AArch64 支持(JEP 391: macOS/AArch64 Port)
更新
工具(Tools):
移除实验性 AOT 和 JIT 编译器(JEP 410: Remove the Experimental AOT and JIT Compiler), 由 GraalVM 替代
用户界面(UI):
新 macOS 渲染引擎(JEP 382: New macOS Rendering Pipeline)
Java 18 - 21
Java 18
主要语言变化
更新
[孵化] 向量 API JEP 417: Vector API (Third Incubator)
[预览]
switch
语句模式匹配 JEP 420: Pattern Matching for switch (Second Preview)默认字符集为 UTF-8 JEP 400:UTF-8 by Default
主要 API 变化
更新
[孵化] 外部 Native 函数和内存 API JEP 419: Foreign Function & Memory API (Second Incubator)
输入/输出(I/O):
UTF-8 作为默认字符 JEP 400: UTF-8 by Default
反射(Reflection):
基于
MethodHandlers
重新实现核心反射API JEP 416: Reimplement Core Reflection with Method Handles
网络(Network):
简单 Web Server JEP 408: Simple Web Server
主要 JVM 变化
更新
不推荐 Finalization, 未来删除 JEP 421: Deprecate Finalization for Removal
工具(Tools)
javadoc: API 文档增加代码片段 JEP 413: Code Snippets in Java API Documentation
Java 19
主要语言变化
更新
[预览] Record 模式(JEP 405: Record Patterns (Preview))
[预览] 虚拟线程(JEP 425: Virtual Threads (Preview))
[预览]
switch
语句模式匹配(JEP 427: Pattern Matching for switch (Third Preview))[孵化] 向量 API(JEP 426: Vector API (Fourth Incubator))
主要 API 变化
更新
[预览] 外部 Native 函数和内存 API(JEP 424: Foreign Function & Memory API (Preview))
[孵化] 结构化并发(JEP 428: Structured Concurrency (Incubator))
StructuredTaskScope
主要 JVM 变化
引入
源码(SourceCode):
Linux/RISC 支持(JEP 422: Linux/RISC-V Port)
Java 20
主要语言变化
引入
[预览] 虚拟线程(JEP 436: Virtual Threads (Second Preview))
[孵化] 作用域值(JEP 429: Scoped Values (Incubator))
[预览] Record 模式(JEP 432: Record Patterns (Second Preview))
[预览]
switch
语句模式匹配(JEP 433: Pattern Matching for switch (Fourth Preview))[孵化] 向量 API(JEP 438: Vector API (Fifth Incubator))
主要 API 变化
更新
[预览] 外部 Native 函数和内存 API(JEP 434: Foreign Function & Memory API (Second Preview))
[孵化] 结构化并发(JEP 437: Structured Concurrency (Second Incubator))
Java 21(LTS)
主要语言变化
引入
虚拟线程(JEP 444: Virtual Threads)
Record 模式(JEP 440: Record Patterns)
switch
语句模式匹配(JEP 441: Pattern Matching for switch)[预览] String 模板(JEP 430: String Templates (Preview))
[预览] 未命名模式和变量(JEP 443: Unnamed Patterns and Variables (Preview))
[预览] 未命名类和实例 main 方法(JEP 445: Unnamed Classes and Instance Main Methods (Preview))
[预览] 作用域值(JEP 446: Scoped Values (Preview))
更新
[孵化] 向量 API(JEP 448: Vector API (Sixth Incubator))
主要 API 变化
引入
集合(Collections): 有序集合(JEP 431: Sequenced Collections)
安全(Security): Key 封装 API(JEP 452: Key Encapsulation Mechanism API)
更新
[预览] 外部 Native 函数和内存 API(JEP 442: Foreign Function & Memory API (Third Preview))
[预览] 结构化并发(JEP 453: Structured Concurrency (Preview))
主要 JVM 变化
更新
垃圾回收(Garbage Collection)
分代 ZGC(JEP 439: Generational ZGC)
目前默认关闭, 未来会设置成默认, 可以通过配置打开:
-XX:+UseZGC -XX:+ZGenerational
源码(SourceCode):
移除 Windows 32 位 x86 实现(JEP 449: Deprecate the Windows 32-bit x86 Port for Removal)
预备禁止动态 Agent 加载(JEP 451: Prepare to Disallow the Dynamic Loading of Agents)
升级Java版本的潜在问题与挑战
个人觉得现代 Java 的使用越来越偏底层, 越来越难, 很多黑科技的出现, 比如指令优化等, 大部分是高阶技能, 所以了解这些高级特性是提升个人竞争力的有效途径.
随着Java从8升级到更新的版本, 我们见证了性能、内存管理以及底层支持等多方面的显著提升. 例如, 字符串压缩、ZGC(Z Garbage Collector)和GraalVM等新特性的引入, 极大地增强了Java平台的能力. 然而, 这种进化并非没有代价, 在决定是否进行版本升级时, 开发者必须仔细考虑以下几项关键因素:
废弃的API和包: 一些旧版API如
sun.misc.BASE64Encoder
已经被删除, 而像javax
这样的包也经历了迁移或弃用. 这意味着依赖这些组件的应用程序可能需要重构以适应新的标准.内部API限制: 对某些内部API(如
Unsafe
)的访问权限变得更加严格, 这可能影响那些直接使用这些API实现特定功能的应用程序.垃圾回收机制的变化: 垃圾回收策略的更新可能会改变应用程序的运行行为, 特别是对于那些高度依赖于特定GC行为的应用而言.
第三方库的兼容性: 随着Java版本的迭代, 第三方库也会相应地更新. 虽然它们会添加新特性, 但同时也会停止支持旧的功能或配置. 例如, Spring Boot 3.0之后不再使用
spring.factories
文件来加载自动配置类, 如果使用的Spring Boot Starter还未适配新版, 则可能导致应用无法正常启动.注解和工具类的变动: 如
@PostConstruct
等注解的处理方式发生变化, 或者新的StackTrace API的引入, 都可能要求第三方框架做出相应的调整, 否则将导致不兼容的问题.项目复杂度的影响: 对于依赖较少的小型项目来说, 升级到更高版本的Java相对简单. 但对于大型项目, 尤其是那些包含多个公共模块的系统, 升级过程可能会非常复杂. 不仅因为内部API的变化, 还因为外部依赖关系的调整需求.
生态系统的演进: 以Spring为例, 其庞大的生态系统使得全面兼容所有JDK版本变得几乎不可能. 因此, 最新的Spring版本已经明确表示不再支持Java 8, 转而拥抱更先进的Java版本, 以减轻历史包袱并推动技术进步.
为了顺利过渡到更新的Java版本, 开发团队应当提前规划, 并确保充分理解上述各项挑战. 此外, 建议对现有代码库进行全面评估, 识别出可能受到版本变更影响的部分, 并制定详细的迁移策略. 对于新的项目开发, 可以充分利用最新Java版本带来的性能优化和其他改进, 但同时也应该意识到随之而来的额外工作量和技术要求.
版本升级兼容常用技巧
添加被移除的包
比较经典就是 javax.xxx
这个包, 有些三方库底层还是用了 javax 的类, 在 JDK 8 可以运行, 升级到 9 以上时就不能用了, 因为这个 javax 已经被移除, 这时候手动引入 javax 依赖, 比如:
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
代码层面逻辑判断兼容
如果使用了将来被移除或者重命名的类, 比如 BASE64Encoder
在 JDK 9 被移除, 为了兼容功能完整性, 需要判断当前运行的 JDK 版本从而在高版本运行环境中切换到其他实现.
String version = System.getProperty("java.version");
if (version.startsWith("1.8")) {
// 使用 BASE64Encoder
} else {
// 高版本实现
}
打包时通过 Profile 区别不同版本
如果一个公共类库比如 common-util
中引用了 util-a:1.0
, common-util
需要在 JDK 8 及以上版本运行, 而 util-a:1.0
只能在 JDK 8 下运行, 只有 util-a:2.0
才支持更高的版本, 但是 util-a:2.0
需要 JDK 11+ 的编译环形, 所以 common-util
不能在 JDK 8 的环境中升级 util-a
到 2.0 版本.
这个 Case 有两个解决方案:
方案1: 在高版本的项目中引入
common-util
, 然后手动排除util-a:1.0
并引入 2.0 版本.优点: 简单
缺点: 一般一个
common-util
不可能只使用了一个三方库, 也不可能只被一两个项目引用, 所以采用此方案需要每个引用到common-util
的项目都手动操作一边, 而且对于未来新增的类库管理不方便.
方案2: 通过 Maven Profile 打包两个版本, 一个给 JDK 8用, 另外一个给更高版本使用. 下面是一个例子, 通过
mvn -Pjdk8 clean install
命令打包出一个classifier
为jdk8
的版本.
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<JAVA_VERSION>21</JAVA_VERSION>
<JAVA_HOME>~/.jdks/azul-21.0.1</JAVA_HOME>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.12</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>jdk8</id>
<properties>
<JAVA_VERSION>1.8</JAVA_VERSION>
<JAVA_HOME>~/.jdks/azul-1.8.0_432</JAVA_HOME>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>jdk8</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.14</version>
</dependency>
</dependencies>
</profile>
</profiles>
其他
Java 模块化问题
遇到类似如下问题:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module
需要加上启动参数打开包权限(其他包的报错类似):
--add-opens java.base/java.lang=ALL-UNNAMED
maven-compiler-plugin
以及 maven-surefire-plugin
插件也可能会遇到此问题, 解决方法也是加参数:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<showWarnings>true</showWarnings>
<fork>true</fork>
<compilerArgs>
<!-- 根据报错添加对应的包 -->
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<argLine>
<!-- 根据情况添加对应的包 -->
--add-opens java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
Spring Boot
Spring Boot 3.0 Migration Guide
Ref
- 3
- 0
-
赞助
微信 -
分享