关键在于控制 javac 实际调用的 JDK 路径(如 JAVA_HOME)和编译参数(如 --release 17),而非仅修改 IDE 的 Language level;--release 比 -source/-target 更安全,可避免高版本 API 调用导致的运行时错误。

怎么让 javac 用指定 JDK 版本编译项目
关键不是改 IDE 界面选项,而是控制 javac 实际调用的 JDK 路径和编译参数。IDE(如 IntelliJ 或 Eclipse)里看到的“Project SDK”和“Language level”只是配置入口,真正起作用的是构建工具或命令行中生效的 JAVA_HOME 和 -source/-target(或 --release)参数。
常见错误:只改了 IDE 的 Language level 为 17,但 JAVA_HOME 指向 JDK 8,结果 maven compile 仍报 Unsupported class file major version 61 —— 因为 Maven 默认用 JAVA_HOME 下的 javac,而非 IDE 设置。
- 命令行编译时,显式指定 JDK 路径:
/path/to/jdk-17/bin/javac -source 17 -target 17 *.java - Maven 项目中,在
pom.xml里配maven-compiler-plugin,和必须与实际 JDK 版本兼容(例如用 JDK 21 编译却设可以,反之不行)17 - Gradle 项目中,优先用
java.toolchain.version = 17(比sourceCompatibility更可靠),它会自动选匹配的 JDK 并传递正确参数
--release 比 -source/-target 更安全吗
是的,尤其在跨 JDK 版本构建时。-source 17 -target 17 只控制语法和字节码版本,但依然可能调用高版本 JDK 中新增的 API(比如 String.isBlank() 在 JDK 11+ 才有),导致运行时 NoSuchMethodError;而 --release 17 会强制使用 JDK 17 的系统类库 stubs 编译,禁用所有高于该版本的 API 调用。
- 推荐 Maven 用户改用:
--release 17 - 注意:
--release从 JDK 9 引入,JDK 8 不支持;且某些旧构建插件(如老版本 maven-compiler-plugin - 如果你依赖了第三方库中仅在 JDK 21+ 存在的 API(如
SequencedCollection),就不能用--release 17,必须降级 API 使用或升级目标版本
IDEA 里改了 Language level 还报错?检查这三处
IntelliJ 的设置分散在多个地方,改一处漏一处就会失效:
立即学习“Java免费学习笔记(深入)”;
- Project Settings → Project → Project SDK:决定 IDE 内置编译器用哪个 JDK(影响 “Build → Compile” 快捷键)
- Project Settings → Project → Project language level:只控制语法高亮和代码补全提示,不影响实际编译输出
- Build → Compiler → Java Compiler → Project bytecode version:这个才真正控制 IDE 编译生成的 class 文件版本,必须和 SDK 匹配(例如 SDK 是 JDK 17,这里不能填 1.8)
如果用 Maven 导入项目,IDEA 还会读取 pom.xml 中的 maven-compiler-plugin 配置,并可能覆盖上述设置——此时手动改 IDEA 设置无效,得去改 pom。
为什么 java -version 和 javac -version 显示不同版本
说明 PATH 和 JAVA_HOME 没对齐。java 命令走 PATH 查找,javac 通常由 JAVA_HOME 决定(尤其 Maven/Gradle 默认行为)。典型场景:系统装了 JDK 8 和 JDK 17,JAVA_HOME=/usr/lib/jvm/java-8-openjdk,但 PATH 里把 JDK 17 的 bin 放前面了。
- 查清当前生效的路径:
which java、which javac、echo $JAVA_HOME - Maven 构建时加
-X参数看 debug 日志,搜索Using Java version行,确认它实际调用的是哪个javac - CI 环境(如 GitHub Actions)中,别只设
setup-java的java-version,还要确保后续步骤没被缓存的$JAVA_HOME干扰
最稳的做法:统一用 JAVA_HOME 控制,删掉 PATH 中所有 JDK bin 目录,只保留 $JAVA_HOME/bin。










