必须在构建配置中显式声明JDK版本,仅靠README无效;Maven需用maven-compiler-plugin配置source/target/release,Gradle推荐java.toolchain;还需记录JDK发行版及构建号以保障行为一致性。

项目中必须明确声明所需 JDK 版本,否则 CI/CD 构建失败、本地编译不一致、甚至运行时 NoClassDefFoundError 都可能悄无声息地发生。
为什么不能只靠 README 写一句“需 JDK 17”
README 不会被构建工具读取,mvn compile 或 gradle build 完全无视它。JDK 版本约束必须嵌入到构建配置中,由工具在解析阶段就校验。
- Java 编译器(
javac)本身不强制版本兼容性——它允许用 JDK 21 编译出 class 文件目标为-target 8,但源码里用了record或switch表达式就会直接报错 - IDE(如 IntelliJ)可能根据
pom.xml或build.gradle自动切换 SDK,但若配置缺失或写错,它就默认用当前JAVA_HOME,而这个值在不同机器上完全不可控 - CI 流水线(GitHub Actions / Jenkins)通常重装环境,没声明 = 用系统默认 JDK(可能是 11 或 17,也可能突然升级成 21)
Maven 项目:用 maven-compiler-plugin 锁定源码与字节码版本
仅靠 java.version 属性或 properties 块不够,必须显式配置插件的 source 和 target(Maven 3.8+ 还要加 release)。
<plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-compiler-plugin</artifactid><version>3.13.0</version><configuration><source>17</source><target>17</target><!-- 推荐加上,防止意外使用高版本 API --><release>17</release></configuration></plugin>
-
控制语法支持(如是否允许var、sealed) -
控制生成的 class 文件版本(影响 JVM 加载) -
是关键:它禁用所有非 JDK 17 标准 API(比如不会偷偷调用jdk.internal.*),且无需设置bootclasspath - 注意:Maven 3.8.1+ 才完整支持
release=17;旧版本需配合和true 指向 JDK 17 的javac
Gradle 项目:在 java 插件块中声明 toolchain
Gradle 从 6.7 开始推荐用 java.toolchain,它比 sourceCompatibility 更可靠——后者只影响编译参数,前者会主动查找并调用匹配的 JDK。
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
- Gradle 会自动扫描
JAVA_HOME、PATH、SDKMAN、~/.sdkman/candidates/java等位置,找到首个符合的 JDK 17 - 若找不到,构建直接失败,并提示 “No matching toolchain found”,而不是降级使用其他版本
- 搭配
org.gradle.java.installations.auto-detect=true(默认开启)和org.gradle.java.installations.from-env-vars=JAVA_HOME可增强定位能力 - 避免写
sourceCompatibility = '17'单独一行——它不触发 JDK 查找,容易掩盖环境不一致问题
额外但关键:记录 JDK 发行版来源(OpenJDK vs Oracle vs vendor)
同一 JDK 大版本下,不同发行版的行为差异可能引发线上事故。例如:
-
Red Hat build of OpenJDK默认启用JFR,而某些 Alpine 镜像中的Adoptium构建可能未包含 JFR 模块 -
Amazon Corretto 17对容器内存限制(cgroup v2)的支持比早期 OpenJDK 17 GA 更完善 - Oracle JDK 商业版的 GC 日志格式和诊断命令(
jcmd)输出字段可能与社区版略有不同
建议在项目根目录放一个 .java-version(供 SDKMAN 识别)或 java-distribution.txt,内容类似:
openjdk-17.0.2+8 vendor: Eclipse Adoptium url: https://adoptium.net/releases.html?version=17
真正容易被忽略的是:**JDK 版本号里的构建号(如 17.0.2+8)和供应商标识,比主版本号更能决定行为一致性。一次 patch 升级可能修复关键的 TLS handshake bug,也可能引入新的 JIT 编译器 regressions。**











