多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

JDK 11 安装与环境变量配置全攻略:多版本共存与常见问题排查

JDK 11 安装与环境变量配置全攻略:多版本共存与常见问题排查 1. 为什么 JDK 11 依然是很多项目的首选版本JDK 11 是 Java 发展史上一个很特殊的存在。它上承 JDK 8 这个“钉子户”版本下接 JDK 17、JDK 21 这些新贵自己却卡在中间成了不少团队长期停留的落脚点。我身边做后端的朋友十个里面至少有三四个的生产环境还跑在 JDK 11 上原因很实在它既是长期支持版本LTS又比 JDK 8 多了不少现代语言特性同时生态兼容性已经打磨得足够成熟。先把概念说清楚。JDK 全称 Java Development Kit是开发 Java 程序必须装的工具包里面包含了编译器 javac、运行时环境 JRE、以及一堆调试和打包工具。很多人会把 JDK 和 JRE 搞混简单类比一下JRE 是“只能看戏的观众席”JDK 是“能上台演戏还能改剧本的后台”。你要写代码、编译代码就必须装 JDK如果只是运行别人打包好的程序装 JRE 就够了。不过现在官方基本都推荐直接装 JDK省得来回折腾。那 JDK 11 到底解决了什么问题最直接的一点它是 JDK 8 之后第一个 LTS 版本。JDK 9 和 JDK 10 都是过渡性的非 LTS 版本生命周期短得可怜企业根本不敢往生产环境上放。JDK 11 在 2018 年 9 月发布官方承诺长期维护这就给了团队一个稳定的升级目标。相比 JDK 8它带来了几个实打实的好处局部变量类型推断var 关键字、HttpClient 标准化、String 类新增了一堆实用方法isBlank、lines、strip 等、单文件源码直接运行java Hello.java 就能跑不用先 javac。这些特性在日常开发里用起来是真的顺手。适合谁来参考这篇内容三类人最需要第一类是刚入门 Java、被“去哪下载 JDK”这个问题卡住的新手第二类是需要在多版本 JDK 之间切换、被环境变量折磨过的开发者第三类是负责给团队或服务器统一配置 Java 环境、需要一份可靠操作流程的人。下面我会把下载、安装、环境变量配置、多版本共存、常见报错排查这几块全部拆开讲尽量做到你照着做就能跑通。2. 下载渠道与版本选择的门道2.1 官方渠道和第三方发行版的区别搜“JDK 下载”的时候你会看到一大堆结果有官方的有各种发行版的还有一堆来路不明的下载站。这里必须先把渠道讲清楚因为装错来源的 JDK轻则版本不对重则夹带私货。最主流的是官方渠道提供的 OpenJDK 构建版本。除此之外还有几个常见的发行版Eclipse Temurin原 AdoptOpenJDK、Amazon Corretto、Azul Zulu、Microsoft Build of OpenJDK、阿里巴巴的 Dragonwell 等。这些发行版本质上都是基于 OpenJDK 源码构建的区别在于背后的维护方、更新频率、以及是否附带一些额外的商业支持。那到底选哪个我的经验是这样个人学习、本地开发随便选一个主流发行版都行Temurin 和 Corretto 用得最多文档也全。企业生产环境优先考虑有长期安全更新承诺的发行版Corretto 和 Temurin 都是稳妥选择。云服务器部署很多云厂商的镜像里已经预装了对应发行版直接用系统包管理器装最省事。注意尽量不要从来路不明的“软件下载站”下 JDK那些站点经常把安装包重新打包甚至捆绑其他东西。认准官方或知名发行版的官方页面。2.2 版本号背后的含义看到“JDK 11.0.20”这种版本号很多人不知道后面那串数字是什么意思。拆开看11 是主版本号0 是次版本号20 是安全更新版本号。每次官方发布安全补丁最后那个数字就会加一。所以 11.0.20 比 11.0.19 新修复了更多安全问题。这里有个坑要提醒不要以为装了 JDK 11 就一劳永逸了。安全更新是需要持续跟进的尤其是暴露在公网的服务。我见过不少团队装完某个小版本就再也没更新过结果几年后爆出安全漏洞才手忙脚乱。建议至少每个季度检查一次有没有新的安全更新版本。另外下载页面通常会让你选操作系统Windows、macOS、Linux、架构x64、aarch64和安装包类型安装版 exe/msi、压缩包 zip/tar.gz。这里的选择直接影响后面怎么装下一节详细说。2.3 安装版和压缩包怎么选这是新手最容易纠结的地方。两种形式各有适用场景类型优点缺点适合场景安装版exe/msi/dmg自动配置部分环境、有向导卸载不干净、路径固定纯新手、单版本压缩包zip/tar.gz解压即用、路径自由、易多版本共存需手动配环境变量开发者、多版本切换我个人的强烈建议是用压缩包。原因很简单压缩包解压到哪个目录你说了算想装几个版本就解压几份切换的时候改一下环境变量就行卸载的时候直接删文件夹干干净净。安装版虽然省事但它会往系统里写注册表、写默认路径多版本共存的时候特别容易打架。3. 手把手完成 JDK 11 安装与环境变量配置3.1 Windows 下的完整操作流程先说 Windows因为用的人最多踩坑的也最多。第一步下载压缩包。去你选定的发行版官方页面找到 JDK 11 的 Windows x64 压缩包zip 格式下载下来。假设你下载到了D:\downloads目录。第二步解压到一个固定目录。我习惯放在D:\dev\jdk\下面解压后路径类似D:\dev\jdk\jdk-11.0.20。注意路径里不要有中文和空格这是很多莫名其妙的报错的根源。我见过有人解压到“我的文档”里结果各种工具识别不了排查半天。第三步配置环境变量。右键“此电脑” → 属性 → 高级系统设置 → 环境变量。这里要配两个东西新建系统变量JAVA_HOME值填D:\dev\jdk\jdk-11.0.20注意不要带\bin。编辑系统变量Path新增一条%JAVA_HOME%\bin。为什么要用JAVA_HOME而不是直接把 bin 路径写进 Path因为很多工具Maven、Gradle、Tomcat都依赖JAVA_HOME这个变量来定位 JDK。你只配 Path 的话命令行能用 java但构建工具可能找不到 JDK。这是新手最常犯的错误之一。第四步验证。打开一个新的命令行窗口一定要新开旧窗口读不到新环境变量依次输入java -version javac -version echo %JAVA_HOME%如果java -version输出类似openjdk version 11.0.20javac -version输出javac 11.0.20echo %JAVA_HOME%输出你配的路径那就成功了。提示如果java -version显示的版本和你装的不一样八成是系统里还有别的 Java 在 Path 里排在前面。这时候要检查 Path 的顺序把%JAVA_HOME%\bin往上挪。3.2 macOS 和 Linux 下的配置方式macOS 现在分 Intel 芯片和 Apple 芯片下载的时候要选对架构。装完之后环境变量的配置方式和 Linux 类似都是改 shell 配置文件。Linux 下以 bash 为例编辑~/.bashrc或~/.bash_profile加上export JAVA_HOME/opt/dev/jdk/jdk-11.0.20 export PATH$JAVA_HOME/bin:$PATH然后执行source ~/.bashrc让它生效。macOS 如果用的是 zsh现在默认就是改的是~/.zshrc内容一样。这里有个细节$JAVA_HOME/bin要放在$PATH的前面这样才会优先使用你指定的 JDK。如果放在后面系统自带的 Java 可能会抢先。验证方式和 Windows 一样java -version和javac -version都跑一遍。macOS 上还可以用/usr/libexec/java_home -V列出系统里所有已安装的 JDK这个命令挺好用。3.3 环境变量配置失败的排查思路“jdk 环境变量配置失败”是搜索量极高的一个问题我把最常见的几种情况列出来现象可能原因解决办法java 不是内部或外部命令Path 没配或没生效检查 Path重开命令行java 能用但 javac 不行只配了 JRE 或 Path 指向错误确认指向 JDK 的 bin版本和预期不符多个 Java 冲突调整 Path 顺序JAVA_HOME 无效路径带 bin 或带引号去掉 bin 和引号改了没反应没重开终端关闭所有终端重开我踩过最深的一个坑是在 Windows 上配完环境变量命令行里怎么都不生效折腾了半小时才发现是之前开着的命令行窗口没关。环境变量是进程启动时读取的已经开着的窗口不会自动刷新。这个教训让我养成了“改完环境变量必重开终端”的习惯。4. 多版本 JDK 共存的实战方案4.1 为什么需要多个 JDK现实开发中你很可能同时面对多个项目老项目跑在 JDK 8 上新项目用 JDK 17手上还有个需要 JDK 11 的。这时候如果系统里只有一个 JDK就会陷入“装了新的旧的跑不了”的困境。多版本共存的核心思路是每个版本解压到独立目录通过切换JAVA_HOME和PATH来决定当前用哪个。听起来简单但手动改环境变量太麻烦所以需要一些技巧。4.2 Windows 下的切换脚本在 Windows 上我习惯写几个批处理脚本放在一个固定目录需要切换的时候双击运行。比如use-jdk11.batecho off setx JAVA_HOME D:\dev\jdk\jdk-11.0.20 setx PATH %%JAVA_HOME%%\bin;%PATH% echo JDK 11 activated. Please reopen your terminal.注意setx是永久设置环境变量但它有个特点设置后当前窗口不生效需要新开窗口。而且setx设置 PATH 的时候要小心如果直接把整个 PATH 覆盖掉会出大问题所以脚本里用了%PATH%拼接。不过更稳妥的做法是只改JAVA_HOME然后让 Path 里始终保留%JAVA_HOME%\bin这一条这样切换JAVA_HOME就等于切换了 JDK。这个思路更优雅Path 里只写%JAVA_HOME%\bin切换脚本只改JAVA_HOME的值。这样无论怎么切Path 都不用动。4.3 Linux/macOS 下的 alias 方案在类 Unix 系统上用 alias 切换最方便。在~/.zshrc或~/.bashrc里加上export JAVA_HOME_8/opt/dev/jdk/jdk-8 export JAVA_HOME_11/opt/dev/jdk/jdk-11.0.20 export JAVA_HOME_17/opt/dev/jdk/jdk-17 alias jdk8export JAVA_HOME$JAVA_HOME_8 export PATH$JAVA_HOME/bin:$PATH alias jdk11export JAVA_HOME$JAVA_HOME_11 export PATH$JAVA_HOME/bin:$PATH alias jdk17export JAVA_HOME$JAVA_HOME_17 export PATH$JAVA_HOME/bin:$PATH export JAVA_HOME$JAVA_HOME_11 export PATH$JAVA_HOME/bin:$PATH这样每次想切换敲一下jdk8或jdk17就行。不过要注意alias 只在当前 shell 会话生效新开的窗口会回到默认版本。如果你希望某个项目目录自动用特定版本可以结合 direnv 这类工具进入目录自动切换。提示切换完记得用java -version确认一下别想当然以为切成功了。我有次 alias 写错了变量名结果切了个寂寞编译报错才发现。4.4 IDE 里的 JDK 配置命令行切好了IDE 里还得单独配。以常见的 IntelliJ IDEA 为例项目级别的 JDK 在 File → Project Structure → Project SDK 里设置可以指向任意一个 JDK 目录和系统环境变量互不影响。这意味着你完全可以让命令行用 JDK 11而某个项目在 IDE 里用 JDK 17。这里有个经验IDE 里配置 JDK 时直接指向解压目录即可不需要依赖JAVA_HOME。所以多版本共存时IDE 反而是最省心的每个项目各配各的。真正麻烦的是命令行构建工具Maven、Gradle它们默认读JAVA_HOME所以切换脚本主要服务的是这些场景。5. 常见问题与排查技巧实录5.1 找不到 JDK 的几种典型场景“找不到 jdk”这个报错背后可能是好几种不同的原因得分开看。第一种命令行报java: command not found。这是环境变量没配好回到第 3 节检查 Path 和 JAVA_HOME。第二种IDE 启动时报找不到 JDK。这通常是 IDE 自己的配置问题去 IDE 的设置里手动指定 JDK 路径即可和系统环境变量无关。第三种构建工具报No compiler is provided in this environment。这个报错的意思是当前用的是 JRE 而不是 JDK因为 JRE 里没有 javac。解决办法是确认JAVA_HOME指向的是 JDK 目录而不是 JRE 目录。有些安装包会把 JDK 和 JRE 装在一起容易指错。第四种服务器上跑脚本报找不到 Java。服务器环境往往更复杂可能是脚本里写死了某个路径或者用的是非交互式 shell 读不到环境变量。这种情况建议在脚本里显式指定JAVA_HOME别依赖全局配置。5.2 版本冲突与降级处理“jdk 降级到 17”这类需求通常是因为某个框架或工具对高版本 JDK 支持不好。降级本身不难难的是降完之后其他东西别崩。我的做法是降级前先确认哪些项目依赖当前版本别一刀切。如果只是某个工具需要低版本优先考虑给那个工具单独指定 JDK而不是把全局降下去。比如 Maven 可以在pom.xml里通过maven.compiler.source和maven.compiler.target指定编译版本但注意这只是指定编译目标运行时的 JDK 还是JAVA_HOME决定的。真正要全局降级时按第 4 节的方法切换即可。切换后建议把常用项目都编译一遍确认没有因为版本变化导致的兼容问题。JDK 高版本往低版本降最容易出问题的是用了高版本才有的 API编译时会直接报错这种反而好发现麻烦的是运行时行为差异比如某些集合类的默认行为变化这种要靠测试覆盖。5.3 服务器环境的特殊处理在服务器上配 JDK和本地开发有几个明显区别。第一服务器通常没有图形界面只能用命令行操作所以压缩包方式几乎是唯一选择。第二服务器上可能同时跑着多个服务每个服务依赖的 JDK 版本可能不同。这时候不要用全局环境变量而是给每个服务单独指定。比如启动脚本里写export JAVA_HOME/opt/dev/jdk/jdk-11.0.20 export PATH$JAVA_HOME/bin:$PATH java -jar myapp.jar这样每个服务用自己的 JDK互不干扰。第三服务器要考虑权限问题。JDK 目录的属主和权限要设对否则服务账户可能读不了。一般建议放在/opt或/usr/local下属主设为运行服务的账户。第四别忘了安全更新。服务器上的 JDK 一旦有安全补丁要尽快跟进。可以订阅对应发行版的安全公告或者定期手动检查版本号。5.4 常见问题速查表问题排查方向快速解决java 命令找不到环境变量检查 Path 和 JAVA_HOMEjavac 命令找不到指向了 JREJAVA_HOME 改指 JDK版本不对多版本冲突调整 Path 顺序IDE 找不到 JDKIDE 配置手动指定路径构建工具报错JAVA_HOME 未设显式配置 JAVA_HOME切换后不生效终端未重开关闭所有终端重开路径含中文报错路径问题换纯英文路径6. 几个容易被忽略的实操细节6.1 关于 JAVA_HOME 的写法JAVA_HOME的值到底要不要带bin答案是不带。它应该指向 JDK 的根目录比如D:\dev\jdk\jdk-11.0.20。然后 Path 里用%JAVA_HOME%\bin来引用。这个约定是行业通用的几乎所有 Java 工具都按这个规则找 JDK。如果你把JAVA_HOME配成了带 bin 的路径很多工具会找不到因为它们会在JAVA_HOME后面再拼/bin。还有一个细节路径结尾不要加反斜杠。D:\dev\jdk\jdk-11.0.20\和D:\dev\jdk\jdk-11.0.20在某些工具里行为不一样稳妥起见不加。6.2 关于 Path 的顺序Path 是个列表系统按顺序查找。如果你装了多个 JavaPath 里排在前面的会优先被找到。所以想让某个版本生效就把它对应的 bin 放到最前面。这也是为什么切换脚本里用$JAVA_HOME/bin:$PATH而不是$PATH:$JAVA_HOME/bin——前者把新版本插到最前面后者插到最后面可能被旧的抢先。6.3 关于验证的完整性很多人验证 JDK 只跑java -version这不够。完整的验证应该包括java -version javac -version echo $JAVA_HOME # Windows 用 echo %JAVA_HOME%三个都对了才算真正配好。只跑 java 的话可能你用的是 JRE 而不是 JDK编译的时候才发现问题。6.4 关于卸载卸载 JDK 时如果用压缩包方式装的直接删目录就行然后把环境变量清理掉。如果用安装版装的走系统卸载程序但要注意它可能留下一些残留的配置。卸载后建议检查一下 Path 里有没有残留的 Java 路径有的话手动删掉否则可能指向一个不存在的目录导致奇怪的报错。我在实际使用中的一个体会是JDK 这东西装的时候多花十分钟把环境变量理清楚后面能省下几十个小时的排查时间。尤其是多版本共存的情况一开始就规划好目录结构和切换方案比事后补救轻松得多。另外养成记录的习惯把自己机器上的 JDK 版本、路径、切换方式写个简单的笔记换电脑或者帮同事配环境的时候直接照着来效率高很多。
返回列表