1. 项目概述:为什么在 Ubuntu 18.04 上用apt装 Java 不是“点几下就完事”的事
在 Ubuntu 18.04 环境下执行sudo apt install default-jre或sudo apt install openjdk-11-jdk,表面看只是敲两行命令的事——但如果你真这么干了,十有八九会在后续开发中踩进三个深坑:一是 JDK 版本与项目要求严重错配(比如 Spring Boot 2.7 要求 JDK 11+,而default-jre在 18.04 默认装的是 OpenJDK 10);二是环境变量JAVA_HOME指向错误路径,导致 Maven 编译报java: 错误: 不支持发行版本 5;三是多个 JDK 并存时update-alternatives配置混乱,java -version和javac -version显示不同版本,IDEA 或 VS Code 直接拒绝识别 SDK。我去年帮团队迁移一个遗留的 Java Web 项目到新服务器,就是卡在这三步上整整两天——不是命令不会敲,而是敲完之后系统“看起来装好了”,实际连javac都编译不出.class文件。Ubuntu 18.04 的生命周期虽已结束(2023年4月终止标准支持),但大量企业内网测试机、CI/CD 构建节点、老旧 Docker 基础镜像仍在使用它,它的 APT 包管理机制和 Java 生态的版本演进节奏存在天然错位。所以这不是一个“安装教程”,而是一份面向真实生产场景的Java 运行时环境精准部署指南:它要解决的不是“能不能运行 HelloWorld”,而是“能否让 Maven、Gradle、Spring Boot、Lombok、JUnit 5 全部协同工作”。核心关键词Java、apt、Ubuntu 18.04组合起来,本质是在一个受限更新源、固定软件仓库、无 Snap 支持的老 LTS 系统上,构建可复现、可验证、可审计的 Java 开发基础链路。适合正在维护旧系统、接手遗留项目、或需要在 CI 流水线中稳定复现构建环境的运维工程师、后端开发、DevOps 工程师,以及备考java面试题时需要快速搭建本地调试环境的求职者——毕竟,java基础和java环境配置是所有java面试八股文的第一道门槛。
2. 内容整体设计与思路拆解:为什么不用 SDKMAN?为什么必须用apt?为什么版本选择比安装动作更重要?
2.1 为什么坚持用apt而非 SDKMAN 或手动解压包?
有人会问:既然apt在 Ubuntu 18.04 上版本陈旧,为什么不直接用 SDKMAN 安装最新版 OpenJDK?答案很现实:稳定性优先于新鲜度。SDKMAN 是一个 Shell 脚本管理器,它下载的 JDK 是上游厂商(Adoptium、Amazon Corretto、Red Hat)提供的二进制包,不经过 Ubuntu 官方仓库签名和依赖校验。在企业级 CI/CD 场景中,安全合规要求所有软件包必须来自可信源、具备 GPG 签名、能被apt list --installed审计。apt安装的 OpenJDK 包(如openjdk-11-jdk-headless)由 Ubuntu 官方维护,其.deb包内置了完整的postinst脚本,自动注册update-alternatives条目、创建/usr/lib/jvm/java-11-openjdk-amd64符号链接、设置默认JAVA_HOME路径,并与系统级工具(如update-java-alternatives)深度集成。我实测过:在 Jenkins slave 节点上用 SDKMAN 安装 JDK 17,当执行mvn clean compile时,Maven 会因找不到tools.jar(JDK 9+ 已移除)或jmods目录结构异常而失败;而apt安装的openjdk-11-jdk包,其jmods目录位于/usr/lib/jvm/java-11-openjdk-amd64/jmods/,且JAVA_HOME自动指向该路径,Maven 插件无需额外配置即可识别。更关键的是,apt安装的 JDK 会随sudo apt upgrade自动接收安全补丁(如 CVE-2021-2341 的修复),而 SDKMAN 安装的 JDK 需手动sdk upgrade java,极易遗漏。所以,apt不是“落后”,而是在确定性、可审计性、可维护性上的最优解。
2.2 为什么 Ubuntu 18.04 的default-jre是个陷阱?
default-jre是一个元包(metapackage),它不包含任何实际代码,只声明对某个具体 JDK 包的依赖。在 Ubuntu 18.04 的官方仓库中,default-jre依赖的是openjdk-10-jre(2018年4月发布),而openjdk-10已于2018年10月停止维护,且不支持 Java Platform Module System(JPMS),无法运行基于 Java 11+ 编译的模块化应用。更致命的是,default-jre的依赖关系是“软绑定”——当你执行sudo apt install default-jre时,APT 解析器会锁定openjdk-10-jre,即使你后续添加了第三方仓库(如 Azul 的 Zulu JDK),default-jre也不会自动升级到openjdk-11-jre。我曾遇到一个案例:某团队在 18.04 上部署 Spring Boot 2.3 应用,application.properties中配置了spring.profiles.active=prod,结果启动时报java.lang.UnsupportedClassVersionError: Unsupported major.minor version 55.0(即 Java 11 字节码)。排查发现,java -version显示openjdk version "10.0.2",而mvn -v却显示Java version: 11.0.12——因为 Maven 的JAVA_HOME被手动设为/usr/lib/jvm/java-11-openjdk-amd64,但系统默认java命令仍指向 JDK 10。这就是default-jre带来的版本割裂。因此,我们必须绕过default-jre,直接指定具体版本的 JDK 包名,这是确保环境纯净的第一步。
2.3 为什么 JDK 11 是 Ubuntu 18.04 的黄金平衡点?
Ubuntu 18.04 的 APT 仓库中,官方支持的 OpenJDK 版本有三个:openjdk-8-jdk(LTS)、openjdk-10-jdk(EOL)、openjdk-11-jdk(LTS)。JDK 8 虽稳定,但已不支持var关键字、Optional.orElseThrow()等现代语法,且 Spring Boot 3.x 完全弃用;JDK 10 是短命版本,仅维护6个月;JDK 11 是 Oracle 的长期支持版本(LTS),也是 Ubuntu 18.04 官方仓库中唯一同时满足“LTS”、“模块化支持”、“主流框架兼容”、“安全更新持续”四大条件的版本。从java面试问题大全及答案大全角度看,JDK 11 引入的String.repeat()、Files.readString()、HttpClient新 API,已是java基础必考内容。更重要的是,openjdk-11-jdk在 18.04 仓库中提供了完整的-jdk(含编译器)、-jre(仅运行时)、-jdk-headless(无图形界面,适合服务器)三个变体,我们可根据场景精准选择。例如,在 CI 构建节点上,应安装openjdk-11-jdk-headless,它比完整版小 40%,且避免因缺少 X11 库导致java.awt相关测试失败。这种“按需安装”思维,远比盲目sudo apt install default-jdk更专业。
3. 核心细节解析与实操要点:apt安装 Java 的 7 个关键环节与避坑指南
3.1 源列表检查:确认universe仓库已启用(否则apt install会报E: Unable to locate package)
Ubuntu 18.04 默认启用main和universe两个核心仓库,但部分最小化安装(如ubuntu-server-minimal)可能禁用universe。openjdk-11-jdk正位于universe仓库中。执行以下命令检查:
grep -E "^(deb|deb-src).*universe" /etc/apt/sources.list正常输出应类似:
deb http://archive.ubuntu.com/ubuntu bionic universe deb http://archive.ubuntu.com/ubuntu bionic-updates universe deb http://security.ubuntu.com/ubuntu bionic-security universe如果无输出,说明universe未启用。此时不能直接编辑/etc/apt/sources.list——因为该文件由apt自动生成,手动修改易被覆盖。正确做法是使用add-apt-repository命令:
sudo add-apt-repository universe sudo apt update提示:
add-apt-repository命令本身可能未安装,此时先执行sudo apt install software-properties-common。这个包提供了add-apt-repository、apt-add-repository等工具,是管理 APT 仓库的基础设施。很多新手看到sudo: apt: command not found就慌了,其实这只是software-properties-common未安装的表象,而非apt本身损坏。
3.2 更新索引前的必要操作:清理过期缓存与修复损坏的包状态
在执行sudo apt update前,必须先清理可能存在的损坏状态。Ubuntu 18.04 的 APT 数据库在长期运行后可能出现dpkg状态不一致,表现为apt update卡在Reading package lists...或报错E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.。此时强行apt install会导致依赖解析失败。标准处理流程是:
# 1. 强制修复中断的 dpkg 配置 sudo dpkg --configure -a # 2. 清理已下载但未安装的 .deb 包(释放磁盘空间) sudo apt clean # 3. 清理旧版本包的缓存(保留当前安装版本的缓存) sudo apt autoclean # 4. 修复损坏的依赖关系(如有) sudo apt --fix-broken install注意:
apt clean会删除/var/cache/apt/archives/下所有.deb文件,包括已安装包的缓存,下次apt install需重新下载;而apt autoclean只删除那些已不再存在于仓库中的旧版本包缓存,更节省带宽。在 CI 环境中,建议用apt clean确保每次构建都从干净状态开始;在开发机上,用apt autoclean更友好。
3.3 JDK 包名精确匹配:区分openjdk-11-jdk、openjdk-11-jdk-headless与openjdk-11-jre
Ubuntu 18.04 仓库中 Java 相关包名有严格语义:
openjdk-11-jdk:完整 JDK,含javac、javadoc、jdb、jmod等全套开发工具,以及 JRE 运行时。适用于开发机。openjdk-11-jdk-headless:精简版 JDK,不含 AWT/Swing 图形界面相关类库(如java.awt.*、javax.swing.*),体积小、启动快,适合服务器、Docker 容器、CI 构建节点。headless模式下,java.awt.GraphicsEnvironment.isHeadless()返回true,可避免因缺少 X11 库导致的java.awt.HeadlessException。openjdk-11-jre:仅 JRE 运行时,不含编译器,无法执行javac。适用于纯 Java 应用部署,但无法编译代码。
执行apt list --all-versions | grep openjdk-11可查看所有可用版本:
openjdk-11-jdk/bionic-updates,now 11.0.22+7-0ubuntu1~18.04.1 amd64 [installed] openjdk-11-jdk-headless/bionic-updates,now 11.0.22+7-0ubuntu1~18.04.1 amd64 [installed] openjdk-11-jre/bionic-updates,now 11.0.22+7-0ubuntu1~18.04.1 amd64注意now后的版本号11.0.22+7-0ubuntu1~18.04.1,其中11.0.22是上游 OpenJDK 版本,+7是 Ubuntu 的打包修订号,0ubuntu1~18.04.1表示这是为 18.04 定制的第一个补丁包。这个版本号至关重要——它决定了是否包含关键安全修复(如java: outofmemoryerror: insufficient memory的 JVM 参数优化补丁)。
3.4 安装命令的精确写法:为什么必须加-y且避免--no-install-recommends
标准安装命令应为:
sudo apt install -y openjdk-11-jdk-headless参数解析:
-y:自动确认所有Y/n提示。在脚本化部署(如 Ansible playbook、Dockerfile)中必须添加,否则会阻塞等待用户输入。--no-install-recommends:不推荐添加。该参数会跳过安装“推荐依赖”(Recommends),而openjdk-11-jdk-headless的 Recommends 包含ca-certificates-java(Java 信任的 CA 证书库)。若跳过,Java 应用在 HTTPS 请求时会因证书链不可信而报javax.net.ssl.SSLHandshakeException。实测:curl https://api.github.com在 JDK 11 下正常,但java -jar myapp.jar访问同一地址却失败,原因正是ca-certificates-java未安装。因此,应让 APT 安装所有 Recommends,确保 TLS 通信可靠。
3.5JAVA_HOME的三种设置方式与优先级判定
JAVA_HOME是 Java 生态的“心脏”,其值错误会导致mvn、gradle、ant全部失效。在 Ubuntu 18.04 上,JAVA_HOME有三层设置机制,按优先级从高到低排列:
Shell 环境变量(最高优先级):在
~/.bashrc或/etc/environment中显式导出。例如:echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64' >> ~/.bashrc source ~/.bashrc此方式对当前用户生效,但需手动
source才能立即生效。APT 包的
postinst脚本(次高优先级):openjdk-11-jdk-headless包的安装脚本会创建/usr/lib/jvm/default-java符号链接,指向/usr/lib/jvm/java-11-openjdk-amd64。许多工具(如 Maven)默认读取此路径。可通过readlink -f /usr/lib/jvm/default-java验证。update-alternatives系统(最低优先级):apt安装 JDK 后,会自动将java、javac等命令注册到update-alternatives,并设置auto模式。此时JAVA_HOME不由alternatives直接控制,但which java的结果会影响某些脚本的推断逻辑。
实操心得:最稳妥的方式是显式设置
JAVA_HOME到/usr/lib/jvm/java-11-openjdk-amd64,而非/usr/lib/jvm/default-java。因为后者是符号链接,当系统安装多个 JDK 时,default-java可能被update-java-alternatives修改,导致JAVA_HOME意外切换。我曾在线上服务器因sudo update-java-alternatives -s java-1.8.0-openjdk-amd64导致JAVA_HOME指向 JDK 8,整个 CI 流水线编译失败,排查耗时3小时。因此,在/etc/environment中写死路径是最可靠的。
3.6 验证安装成功的 5 个必检项
安装完成后,不能只执行java -version就认为万事大吉。必须通过以下 5 项验证,缺一不可:
JVM 版本与供应商:
java -version # 正确输出应为: # openjdk version "11.0.22" 2024-04-16 # OpenJDK Runtime Environment (build 11.0.22+7-0ubuntu1~18.04.1) # OpenJDK 64-Bit Server VM (build 11.0.22+7-0ubuntu1~18.04.1, mixed mode, sharing)JDK 编译器可用性:
javac -version # 必须输出与 `java -version` 相同的版本号,证明 `javac` 已正确安装。JAVA_HOME路径有效性:echo $JAVA_HOME ls -l $JAVA_HOME # 输出应为 `/usr/lib/jvm/java-11-openjdk-amd64`,且目录存在。update-alternatives注册状态:sudo update-alternatives --config java # 应显示 `java-11-openjdk-amd64` 为当前选择项。关键工具链连通性:
# 创建测试文件 echo 'public class Test { public static void main(String[] args) { System.out.println("Hello from JDK 11!"); } }' > Test.java # 编译 javac Test.java # 运行 java Test # 输出 "Hello from JDK 11!" 即成功。
注意:第5项是终极验证。很多教程忽略这一步,导致
java -version正常但javac编译失败(常见于只装了jre未装jdk)。java: 错误: 不支持发行版本 5这类报错,90% 源于javac和java版本不一致,而此测试能直接暴露问题。
3.7 多 JDK 共存管理:update-java-alternatives的正确用法
当系统需同时支持 JDK 8(用于维护老项目)和 JDK 11(用于新项目)时,update-java-alternatives是官方推荐工具。但必须注意其局限性:它只能切换java、javac、javadoc等命令的全局默认版本,不能为不同用户或不同 Shell 会话设置独立版本。操作步骤如下:
# 1. 查看所有已注册的 JDK sudo update-java-alternatives --list # 2. 切换到 JDK 11(假设输出中有 java-1.11.0-openjdk-amd64) sudo update-java-alternatives --set java-1.11.0-openjdk-amd64 # 3. 验证切换结果 java -version javac -version重要警告:
update-java-alternatives会修改/usr/lib/jvm/default-java符号链接,并更新所有alternatives条目。但JAVA_HOME环境变量不会自动更新!如果你在~/.bashrc中硬编码了JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64,那么即使java -version显示 JDK 11,mvn compile仍会使用 JDK 8。因此,多 JDK 环境下,JAVA_HOME必须与update-java-alternatives同步设置。最佳实践是:在~/.bashrc中使用export JAVA_HOME=$(readlink -f /usr/lib/jvm/default-java),这样JAVA_HOME会随default-java链接自动变化。
4. 实操过程与核心环节实现:从零开始的完整部署流水线(含 Dockerfile 示例)
4.1 标准化部署脚本:install-java-11.sh的逐行解析
以下是一个可在任意 Ubuntu 18.04 系统上一键执行的部署脚本,已通过 20+ 台不同配置服务器实测:
#!/bin/bash # install-java-11.sh - Ubuntu 18.04 OpenJDK 11 Headless Installer # 作者:资深 Java 基础设施工程师 # 用途:CI/CD 构建节点、Docker 构建环境、开发机初始化 set -e # 任一命令失败即退出 echo "=== 步骤1:启用 universe 仓库 ===" sudo add-apt-repository -y universe echo "=== 步骤2:修复 dpkg 状态 ===" sudo dpkg --configure -a echo "=== 步骤3:清理 APT 缓存 ===" sudo apt clean sudo apt autoclean echo "=== 步骤4:更新软件包索引 ===" sudo apt update echo "=== 步骤5:安装 OpenJDK 11 Headless ===" sudo apt install -y openjdk-11-jdk-headless ca-certificates-java echo "=== 步骤6:设置 JAVA_HOME 环境变量 ===" echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64' | sudo tee /etc/profile.d/java11.sh echo 'export PATH=$JAVA_HOME/bin:$PATH' | sudo tee -a /etc/profile.d/java11.sh sudo chmod +x /etc/profile.d/java11.sh echo "=== 步骤7:重载环境变量 ===" source /etc/profile.d/java11.sh echo "=== 步骤8:验证安装 ===" java -version javac -version echo "JAVA_HOME=$JAVA_HOME" echo "=== 安装完成!请执行 'source /etc/profile' 或重启终端生效 ==="脚本关键设计点:
set -e:确保任一环节失败立即终止,避免“半安装”状态。ca-certificates-java显式安装:防止 HTTPS 通信失败。/etc/profile.d/java11.sh:比修改/etc/environment更灵活,.sh文件会被所有 Shell 自动 source。source /etc/profile.d/java11.sh:在脚本内立即生效,方便后续验证。
4.2 Docker 环境适配:Dockerfile中的最小化 Java 基础镜像构建
在 CI/CD 中,常需基于 Ubuntu 18.04 构建 Java 构建镜像。以下Dockerfile是生产环境验证过的最小可行方案:
# 使用官方 Ubuntu 18.04 基础镜像 FROM ubuntu:18.04 # 设置时区和语言环境(避免 Maven 编译时区警告) ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ENV LANG=C.UTF-8 ENV LANGUAGE=C.UTF-8 ENV LC_ALL=C.UTF-8 # 更新源并安装 Java(关键:使用 -qq 减少日志噪音) RUN apt-get update && \ apt-get install -y --no-install-recommends \ openjdk-11-jdk-headless \ ca-certificates-java \ curl \ wget \ git && \ rm -rf /var/lib/apt/lists/* # 设置 JAVA_HOME(Docker 中推荐用 ENV,而非 profile.d) ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 ENV PATH=$JAVA_HOME/bin:$PATH # 验证安装(构建时执行,失败则镜像构建中断) RUN java -version && \ javac -version && \ echo "JAVA_HOME=$JAVA_HOME" && \ test -d "$JAVA_HOME" # 设置工作目录 WORKDIR /workspace # 声明 Java 端口(非必须,但符合 Docker 最佳实践) EXPOSE 8080 # 默认命令 CMD ["java", "-version"]构建命令:
docker build -t ubuntu1804-java11 .实操心得:在 Docker 中,
ENV设置JAVA_HOME比RUN source /etc/profile更可靠,因为后者在构建阶段的 Shell 会话中生效,但不会持久化到镜像层。--no-install-recommends在 Docker 中是安全的,因为我们显式安装了ca-certificates-java,避免了证书问题。
4.3 Maven 与 Gradle 的无缝集成:settings.xml与gradle.properties配置要点
Java 安装完成后,构建工具需明确指定 JDK 路径。Maven 默认读取JAVA_HOME,但某些插件(如maven-compiler-plugin)需显式声明源码和目标版本:
<!-- ~/.m2/settings.xml --> <settings> <profiles> <profile> <id>java11</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <maven.compiler.release>11</maven.compiler.release> </properties> </profile> </profiles> </settings><maven.compiler.release>是关键:它启用--release参数,强制编译器生成与 JDK 11 运行时完全兼容的字节码,避免java: 警告: 源发行版 17 需要目标发行版 17类错误。
Gradle 则在gradle.properties中设置:
# gradle.properties org.gradle.java.home=/usr/lib/jvm/java-11-openjdk-amd64 org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m注意:
org.gradle.java.home必须指向 JDK 目录(含bin/javac),而非 JRE 目录。若指向错误,gradle build会报Could not determine java version from '11.0.22'。
4.4 IDE 集成验证:IntelliJ IDEA 与 VS Code 的 SDK 配置实录
IntelliJ IDEA(2023.1+):
File → Project Structure → Project:设置Project SDK为/usr/lib/jvm/java-11-openjdk-amd64。Project Settings → Modules:确认每个模块的Language level为11。Build → Compiler → Java Compiler:设置Target bytecode version为11。- 关键检查:点击
Project SDK右侧的...,在弹出窗口中点击Test按钮,IDEA 会调用javac -version验证 SDK 可用性。若失败,说明JAVA_HOME或路径有误。
VS Code(配合 Extension Pack for Java):
Ctrl+Shift+P→Java: Configure Java Runtime。- 在
Java Configuration Runtimes页面,点击+ Add Runtime,选择/usr/lib/jvm/java-11-openjdk-amd64。 - 在
Project Settings中,确保java.configuration.runtimes包含:"java.configuration.runtimes": [ { "name": "JavaSE-11", "path": "/usr/lib/jvm/java-11-openjdk-amd64" } ] - 避坑提示:VS Code 的 Java 扩展有时会缓存旧 JDK 路径。若配置后仍报
java: you aren't using a compiler supported by lombok,需关闭所有窗口,删除~/.vscode/extensions/redhat.java-*缓存目录,再重启。
5. 常见问题与排查技巧实录:从sudo apt update失败到java.lang.ExceptionInInitializerError
5.1sudo apt update报错Failed to fetch ... Connection failed的 3 种根因与解法
| 现象 | 根因 | 解决方案 |
|---|---|---|
Err:1 http://archive.ubuntu.com/ubuntu bionic InReleaseConnection failed [IP: 91.189.88.142 80] | DNS 解析失败或网络策略拦截 | 执行sudo nano /etc/resolv.conf,添加nameserver 8.8.8.8,然后sudo systemctl restart systemd-resolved |
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic/InReleaseTemporary failure resolving 'archive.ubuntu.com' | Ubuntu 官方源在部分地区访问不稳定 | 替换为国内镜像源:sudo sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list,再sudo apt update |
E: The repository 'http://security.ubuntu.com/ubuntu bionic-security Release' does not have a Release file. | Ubuntu 18.04 已结束标准支持,bionic-security源需手动启用 ESM(Extended Security Maintenance) | 执行sudo apt install ubuntu-advantage-tools,然后sudo ua attach <token>(需 Canonical 订阅),或改用http://old-releases.ubuntu.com/ubuntu源 |
实操心得:
apt update失败是 Java 安装的第一道关卡。我见过最多的情况是公司防火墙拦截了archive.ubuntu.com的 80 端口,此时必须联系 IT 部门开通,或临时使用代理(但代理配置需在/etc/apt/apt.conf中设置Acquire::http::Proxy "http://proxy:3128";,而非http_proxy环境变量)。
5.2java -version正常但javac -version报command not found的定位流程
此问题表明只安装了 JRE,未安装 JDK。排查步骤:
# 1. 检查已安装的 java 相关包 dpkg -l | grep openjdk # 2. 若输出只有 openjdk-11-jre,则缺失 jdk # 3. 安装完整 jdk sudo apt install -y openjdk-11-jdk-headless # 4. 验证 javac 是否在 PATH 中 ls -l /usr/lib/jvm/java-11-openjdk-amd64/bin/javac echo $PATH | tr ':' '\n' | grep jvm注意:
openjdk-11-jre和openjdk-11-jdk-headless是两个独立包,apt install openjdk-11-jre不会自动安装javac。java基础教程常混淆这点,导致初学者以为java命令存在即代表开发环境完备。
5.3java: 错误: 不支持发行版本 5的 4 层诊断树
这是一个经典版本错配错误,需逐层排查:
graph TD A[报错:不支持发行版本 5] --> B{javac -version} B -->|显示 1.5 或 1.6| C[编译器版本过低] B -->|显示 11| D{java -version} D -->|显示 1.5 或 1.6| E[运行时版本过低] D -->|显示 11| F{pom.xml 或 build.gradle 中 source/target 设置} F -->|设为 1.5| G[构建配置错误] F -->|设为 11| H[IDE 缓存或项目 SDK 未刷新]实际操作中,90% 的案例是H 层:IDE 未识别新安装的 JDK。解决方案:
- IntelliJ:
File → Project Structure → Project → Project SDK,点击右侧...,选择/usr/lib/jvm/java-11-openjdk-amd64,然后Apply。 - VS Code:
Ctrl+Shift+P → Java: Reload Projects。
5.4java.lang.ExceptionInInitializerError与com.sun.tools.javac.code.TypeTag的关联分析
此错误常出现在使用 Lombok 的项目中,根本原因是JDK 版本与 Lombok 版本不兼容。Lombok 1.18.20+ 要求 JDK 11+,而 Ubuntu 18.04 仓库中的openjdk-11-jdk版本为11.0.22,完全兼容。但如果错误信息中包含com.sun.tools.javac.code.TypeTag,说明 Lombok 尝试访问 JDK