做 Java 开发这些年,IDEA + Maven 编译时控制台乱码这个问题,我至少帮同事排查过几十次。说它是小问题吧,真要彻底解决得把源码编码、编译编码、JVM 进程编码、控制台显示编码这一整条链路全部捋顺,少一个环节都不行;说它复杂吧,其实绝大多数场景就是编码约定不一致,改几处配置就能搞定。
今天这篇就当是我的排查笔记,把思路、配置和踩过的坑一次性写全。文章主要面向 Windows 中文环境下用 IDEA 做 Java 开发的读者,包括刚入行的新手,以及被项目里各种编码历史问题折磨已久的老手。只要你按照后面的清单一步步对齐,基本能彻底告别这类乱码。
1. 先搞清楚乱码到底卡在哪一环:编码链条拆解
1.1 一段文字从源码到控制台要经过哪些编码转换
很多人遇到乱码的第一反应是“改 IDEA 的编码设置”,但改完发现该乱还是乱,原因就是没搞懂数据到底经过了多少个环节。我习惯把它拆成一条链路来看。
一条普通的中文信息,从你写在.java文件里,到最终显示在 IDEA 控制台,至少要经过这些环节:
- 源码文件本身的存储编码。也就是
.java文件以什么字节序列存在磁盘上,IDEA 右下角一般会显示当前文件的编码,比如 UTF-8; - 编译时 javac 读取源码使用的编码。这个由 Maven compiler 插件配置或 JVM 默认编码决定;
- Maven 进程自身 JVM 的默认编码。Maven 本质也是跑在 JVM 里的程序,它的日志输出、文件读写都会受到 file.encoding 影响;
- 程序运行时输出中文所采用的编码。System.out 输出字节时,PrintStream 用的编码来自运行进程的默认编码;
- IDEA 控制台窗口用什么样的编码去解码收到的字节流。
打个比方,这一段文字就像一个快递包裹,每一站都需要物流单号来识别。如果某站拿错单号,包裹就会被送到错误的地方。编码问题也一样,数据本身没有坏,是“读取规则”对不上。你看到乱码,本质上就是某一站的解码规则和上一站的编码规则不一致。
所以,“乱码”永远不是一个点的问题,而是链条的问题。这也是为什么单改一个设置往往不能根治。
1.2 JDK 版本变了,乱码规则也变了
这个因素很多老项目容易忽略。如果你用的是 JDK 8、JDK 11,或者 JDK 17,在没有显式指定编码的情况下,JVM 默认使用操作系统平台的编码。Windows 中文版默认就是 GBK。
但从 JDK 18 开始,JEP 400 把 JVM 的默认字符集改成了 UTF-8。也就是说,同样一段代码,同一套配置,你从 JDK 8 切到 JDK 21 后,可能“莫名”就不乱码了。
这不是 IDEA 自动帮你修好了,而是 JVM 默认行为变了。反过来也说明一个问题:如果团队里有人用 JDK 8,有人用 JDK 21,即便代码相同、提交相同,控制台输出的编码表现也可能不一样。很多人遇到“同代码在我这乱码,在同事那里不乱码”的诡异情况,一大半原因是 JDK 版本或系统区域设置不同。
所以排查时,第一步就应该确认当前项目实际使用的 JDK 版本,而不是上来就改配置。
1.3 Windows 中文版的“历史包袱”
Windows 的命令行工具,包括 cmd、批处理脚本、老版本的控制台程序,默认代码页经常是 936,也就是 GBK。很多老工具输出的中文日志都是 GBK 编码。而 IDEA 内部控制台、现代终端工具,默认更倾向于 UTF-8。
这就会造成一个典型现象:同一个 Maven 项目,在 cmd 里运行mvn clean compile,输出的中文可能正常;但放到 IDEA 的控制台里跑,中文全变成乱码。原因是 Maven 进程以 GBK 输出日志,IDEA 控制台却按 UTF-8 去解码。
所以面对乱码,你必须先回答一个问题:是只在 IDEA 里乱,还是在 cmd、PowerShell 里也乱?这个初步判断,直接决定了后面你该改哪里。
2. 全局层面的编码统一配置(IDEA + Maven 基础设置)
2.1 IDEA 的 File Encodings 三件套
IDEA 的编码设置分散在好几个地方,很多人只改了 Project Encoding,结果不够用。最基础的是这里:Settings → Editor → File Encodings。
打开这个页面后,你会看到几个关键项:
- Global Encoding:全局编码,影响所有没有单独指定编码的项目文件;
- Project Encoding:当前项目的编码,这个是最重要的;
- Properties Files:专门针对
.properties文件的编码; - 在页面下方或 IDE 相关设置里,还有 IDE Encoding 和 Console 编码项。
我的建议是,Global、Project、Properties Files 三项全部设置成 UTF-8。很多人只改 Project Encoding,但 Global Encoding 如果不一致,某些新文件或 IDE 创建的配置文件还是会以别的编码保存,后续埋坑。
Properties Files 这一项也别忽略。项目里经常有application.properties、messages.properties这类文件,里面写了中文。IDEA 在这里有一个“Transparent native-to-ascii conversion”的开关,如果你勾选了,IDEA 会把 properties 里的中文自动转成\uXXXX形式的 ASCII 内容保存,这样文件本体是安全的,不会因为编码不一致被破坏。我个人的习惯是打开这个选项,虽然查看时有点不方便,但至少不会出现“properties 保存后中文全变问号”的坑。
除了 File Encodings 页面,新版 IDEA 还会在同一个页面下方提供 Console 编码设置。如果没有找到,可以到Settings → Editor → General → Console里看,不同版本位置略有差异,但思路都一样:把控制台显示编码也固定成 UTF-8。
2.2 Maven 构建编码:pom.xml 里必须写死
很多情况下,IDEA 这边的验证编码已经设成 UTF-8 了,源码文件也显示 UTF-8,但 Maven 编译时依然乱码。问题就出在 Maven 本身并没有拿到“请用 UTF-8 编译”的指令。
Maven 在 Windows 中文系统上,如果 pom.xml 里没有显式声明编码,相关插件会默认采用系统编码,也就是 GBK。javac 会按 GBK 去读你的 UTF-8 源码文件,导致中文字符串直接变乱码,甚至编译报错。
解决办法是在 pom.xml 的<properties>节点里写死编码:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding> </properties>这三项分别影响:
project.build.sourceEncoding:Maven 读取和处理源码、资源文件时使用的编码,也影响 maven-resources-plugin 的资源复制与过滤行为;project.reporting.outputEncoding:影响 Javadoc、测试报告等生成内容的编码;maven.compiler.encoding:传给 maven-compiler-plugin 的编译编码参数,等价于 javac 的-encoding参数。
如果你的项目里已经显式配置了 maven-compiler-plugin,也可以在插件配置里加<encoding>UTF-8</encoding>,效果相同。不过我更推荐在 properties 里统一声明,代码更简洁,团队维护的时候一眼能看到。
2.3 为什么统一用 UTF-8,而不是“跟着系统走”
有人会问,既然 Windows 默认是 GBK,那为什么不用 GBK,反而能避免乱码?
现代开发工具链对 UTF-8 的支持已经非常普及。Git 仓库默认也是 UTF-8 语义,Linux、Docker 容器、CI 构建环境几乎都默认 UTF-8。如果你在 pom 里写死 UTF-8,至少能保证同一份代码在 Windows、macOS、Linux 上编译行为一致。
GBK 的问题在于它属于“本地编码”,换一台英文系统或 Linux 服务器,字符集就变了。团队协作时,一个统一的标准编码非常重要。UTF-8 就是目前最通用的标准。
但这里有一个老项目改造时必须注意的坑:如果项目里大量源码文件本身就是 GBK 存储的,你直接把 pom 改成 UTF-8,反而会让原本好好的中文全部变成乱码。正确做法是,先把所有源码文件确认并转换成 UTF-8,再改 pom。转换前最好用 Git 提交一个备份节点,方便回溯。
3. 卡在 Maven 进程和控制台之间:运行时编码设置
3.1 Maven Runner 的 VM Options,这一步很容易被忽略
如果 pom.xml 里已经写死了 UTF-8,但 IDEA 里跑 Maven 还是乱码,那问题往往出在 Maven 进程本身的 JVM 参数上。
IDEA 里执行 Maven 命令,本质上会拉起一个新的 Java 进程。这个进程的默认字符集如果没有被显式指定,在中文 Windows 上就是 GBK。即便 pom 里设置了 sourceEncoding,某些插件在输出日志时依然可能使用 JVM 默认编码,导致控制台显示乱码。
打开Settings → Build, Execution, Deployment → Build Tools → Maven → Runner,在 VM Options 里加上:
-Dfile.encoding=UTF-8这一步非常关键。很多教程只会告诉你改 File Encodings,结果改了之后发现 Maven 输出日志还是乱码,就是因为这个 Runner 的 JVM 参数没设置。
顺手提一句,MAVEN_OPTS 环境变量对 IDEA 内置的 Maven 运行器基本不生效,因为 IDEA 不是通过命令行调用 mvn 的,而是直接在自己的 Runner 里加载 Maven 运行时。所以不要把希望寄托在 MAVEN_OPTS 上,要改就改上图里的 VM Options。
如果这样还不够,可以在 Runner 的 Environment variables 里再加一个JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8。需要注意的是,设置 JAVA_TOOL_OPTIONS 之后,进程启动时会打印一行Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8,这是正常现象,不用管它。
3.2 IDEA 控制台要以 UTF-8 渲染
改完 Maven Runner 的 VM Options,输出到控制台的字节流已经变成 UTF-8 了,但如果 IDEA 控制台还在用 GBK 解码,照样乱码。
所以还要回过去确认控制台本身的编码。新版 IDEA 里,Settings → Editor → File Encodings页面下方通常有一个 Console 下拉框,把它也设置成 UTF-8。如果你的版本没有这个选项,可以检查Settings → Editor → General → Console,里面一般有 Default Encoding 配置项。
还有一个更彻底的做法:修改 IDEA 自身的 JVM 参数。菜单Help → Edit Custom VM Options,打开后加这两行:
-Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8保存后重启 IDEA。这样整个 IDE 的渲染和输出都会尽量向 UTF-8 靠拢。
不过需要提醒的是,修改 IDEA 自身的 file.encoding 会影响到 IDE 全局行为,包括缓存、日志、插件输出。一般情况下不建议随便加,只有当你确认 Maven、控制台都设置正确但仍然乱码时,再把它当作最后手段。
3.3 用 cmd / PowerShell 跑 mvn 时乱码怎么办
如果你不是在 IDEA 里跑 Maven,而是在命令行直接执行mvn clean compile,那情况又不太一样。
cmd 默认代码页如果是 936,而 Maven 输出的是 UTF-8,控制台会以 GBK 解读 UTF-8 字节,中文自然乱码。最简单的解决办法是先切换代码页:
chcp 65001然后执行 Maven 命令。这个操作只在当前命令行窗口生效,不会影响系统全局。
PowerShell 里还可以这样设置输出编码:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8如果你希望团队里的所有人都能避免这个问题,可以在项目的根目录放一个小脚本,比如mvn-utf8.cmd,内容大致是:
@echo off chcp 65001 > nul mvn %*这样团队成员直接用mvn-utf8.cmd clean compile就能避开乱码,不用每个人都去背 chcp 命令。
3.4 编译通过但日志输出乱码:这是另一个问题
还有一种很常见的场景:编译不报错,IDEA 控制台里编译日志也正常,但程序一运行,System.out 输出的中文全是乱码。这个问题的根源和上面说的编译期不一样,它更多是运行期 JVM 编码或日志框架编码的问题。
如果你的项目使用 Logback,默认情况下 ConsoleAppender 会使用系统平台编码输出,Windows 上就是 GBK。但 IDEA 控制台按 UTF-8 显示,于是中文乱码。解决办法是在 Logback 的配置里显式指定字符集:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <charset>UTF-8</charset> <pattern>%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n</pattern> </encoder> </appender>Log4j2 也类似,在 Console Appender 的 PatternLayout 里配置charset="UTF-8"。
如果是直接用System.out.println输出中文,那就要确保运行程序的 JVM 编码是 UTF-8。在 IDEA 的运行配置,也就是 Run/Debug Configurations 里,也可以给对应 Application 的 VM options 加上-Dfile.encoding=UTF-8。本质上和 Maven Runner 是同一个思路:让 JVM 进程的默认编码对齐成 UTF-8。
这里特别想强调一点:一定要分清楚“编译期乱码”和“运行期乱码”。我见过不少人折腾了半天 pom.xml,结果发现编译日志正常,是自己项目里的 Logback 没配置 charset。方向错了,配置改再多也没用。
4. 实操:从零到干净的编译控制台(完整配置流程)
4.1 先定位是哪一类乱码
动手改配置之前,我强烈建议你先做一次快速定位,避免“闭着眼睛改设置”。
你可以写一个最简单的 Java 类:
public class EncodingCheck { public static void main(String[] args) { System.out.println("中文测试"); System.out.println("file.encoding=" + System.getProperty("file.encoding")); System.out.println("sun.jnu.encoding=" + System.getProperty("sun.jnu.encoding")); } }把它放到项目里,先用 IDEA 直接运行。如果输出中文正常,但file.encoding是 GBK,说明当前运行环境是中文 Windows 默认配置。如果中文本来就是乱码,那就可以直接判断是运行期编码不对。
再观察编译阶段的日志:如果 Maven 编译时插件输出的中文全部乱码,而你的源码运行输出正常,那多半是 Maven 进程编码的问题;如果源码里的中文注释都变成乱码,那大概率是 javac 读取源码时用了错误的编码。
这一步看起来简单,但能帮你省掉大量走弯路的时间。我自己的经验是,90% 的乱码问题,靠这一步就能确定排查方向。
4.2 一步步配置清单(可直接照抄)
假设你已经完成了上面的定位,接下来给你一份可以直接照抄的完整操作清单。这是一套我认为最稳妥的组合:
确认项目 JDK 版本。如果项目跑在 JDK 17 及以下,且操作系统是 Windows 中文版,乱码概率最高;如果项目已经升级到 JDK 18+,默认 UTF-8,但老项目还是要按下面步骤统一。
打开
Settings → Editor → File Encodings,把 Global Encoding、Project Encoding、Properties Files 的编码全部设置为 UTF-8,同时检查 Console 编码是否也为 UTF-8。如果有 IDE Encoding 的选项,也一并设成 UTF-8。检查项目里现有的
.java和.properties文件实际编码。在 IDEA 右下角可以看到当前文件编码,如果有文件显示为 GBK,可以点击并选择 Convert to UTF-8。这一步要小心,转换前先确认文件内容显示正常,最好提前提交一次 Git。在 pom.xml 的
<properties>中加入:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding> </properties>如果项目里有显式配置 maven-compiler-plugin,检查 configuration 里的 encoding 是否为 UTF-8,有些老项目会在里面写死 GBK。确认后保存 pom,在 IDEA 右上角 Maven 面板点击刷新按钮,也就是 Reload All Maven Projects,确保配置重新加载。
打开
Settings → Build, Execution, Deployment → Build Tools → Maven → Runner,在 VM Options 里填写-Dfile.encoding=UTF-8。执行一次
mvn clean compile,观察控制台输出。如果中文正常了,说明问题已经解决。如果依然乱码,继续看下面的排查部分。
这套流程我帮人处理过很多次,绝大多数项目到第 6 步就能看到明显效果。第 7 步如果依然有问题,那就不是常规配置问题,需要再往下深挖。
4.3 系统级 UTF-8 开关:要不要开
有时候会遇到一种顽固情况:IDEA 和 Maven 配置都设置好了,但某个工具或者某个老脚本输出还是 GBK,导致从外部拿到的日志文件、命令行输出依然乱码。
Windows 10/11 提供一个系统级开关:控制面板 → 区域 → 管理语言设置 → 更改系统区域设置 → 勾选“Beta: 使用 Unicode UTF-8 提供全球语言支持”,然后重启电脑。
这个开关的作用是把系统默认字符集切到 UTF-8,很多与控制台、文件路径相关的乱码问题会从根上消失。但我个人不建议在日常开发机上轻易开启,副作用比较明显:
- 一些老版本软件,尤其是中文 Windows 下开发的国产工具,可能会出现界面文字乱码或显示异常;
- GBK 编码的历史文件、日志,打开后会变成乱码;
- 某些依赖系统 Locale 的脚本行为可能改变。
我一直把系统级 UTF-8 开关当成“最后手段”,而不是首选方案。如果是团队协作环境,更不应该为了某个人的问题去强制系统设置。正确顺序应该是:项目统一 UTF-8 → IDEA 配置统一 → Maven Runner 统一 → 系统开关兜底。
5. 常见问题速查与排查技巧
5.1 典型场景速查表
下面整理了几个我实际工作中反复遇到的典型场景,你可以直接对照排查:
| 现象 | 可能原因 | 处理方法 |
|---|---|---|
| 编译插件输出中文乱码,英文正常 | Maven 进程 JVM 默认编码不是 UTF-8 | Maven Runner 的 VM Options 加-Dfile.encoding=UTF-8 |
| 编译日志正常,运行程序后 System.out 输出乱码 | 运行 JVM 编码不是 UTF-8,或日志框架没指定 charset | Run Configuration 的 VM options 加 UTF-8;Logback/Log4j2 配置 charset |
| 源码里的中文注释乱码 | javac 读取源码时使用的编码与文件实际编码不符 | 确认源码文件实际编码,转换文件后统一 UTF-8;在 pom 里写死 sourceEncoding |
| properties 文件中文乱码 | Properties Files 编码设置不对 | File Encodings 里单独设置 Properties Files 为 UTF-8 |
| cmd 里跑 mvn 乱码,IDEA 里正常 | 命令行代码页与 Maven 输出编码不一致 | 执行chcp 65001再运行 mvn |
| 同一套代码,同事不乱码,你乱码 | JDK 版本、系统区域设置或 IDEA 版本不同 | 对比 JDK、系统区域、IDEA 编码设置 |
| 改了 pom 后配置没生效 | 没有重新加载 Maven 项目 | IDEA 里 Reload All Maven Projects |
这张表不是标准意义上的“速查全部”,但覆盖了我见过的大部分场景。如果你遇到的现象不在表里,大概率还是链条里某个环节没对齐,继续用第 5.2 节的思路排查。
5.2 排查乱码的“三板斧”
我把我自己总结的排查思路叫做“三板斧”,遇到乱码就往这三点上套。
第一板斧:确认乱码是在 IDEA 内,还是 IDEA 外也乱。如果 cmd、PowerShell、甚至文本编辑器打开同一份日志都是乱码,那问题大概率出在产生日志的一方,Maven 或运行中的程序。如果外部正常,只有 IDEA 控制台乱码,那就是 IDEA 控制台解码编码的问题。
第二板斧:确认是编译日志乱码,还是运行程序后的输出乱码。编译日志乱码先查 Maven Runner 和 pom 编码;运行输出乱码先查 Logback/Log4j2 charset 和 Run Configuration 的 VM options。这两个方向的配置项完全是两套,混在一起排查效率很低。
第三板斧:确认配置改动之后是否重新加载。pom.xml 改了,一定要在 Maven 面板点刷新;IDEA 设置改了,有些需要重启 IDE 才生效。磨刀不误砍柴工,不要改了配置马上跑,报怨“没用”,很可能只是没生效。
在实际操作中,还有一个非常实用的命令,可以快速查看当前 Java 进程的实际编码:
java -XshowSettings:properties -version 2>&1 | findstr encoding在 IDE 的终端里运行,能直接看到 file.encoding 和 sun.jnu.encoding 的值。这两个值一个管文件读写,一个管文件名和路径。如果 file.encoding 显示的不是 UTF-8,说明进程的默认编码还是系统编码,需要按上面的方式显式指定。
5.3 终极兜底:在项目里统一声明 JVM 编码
如果公司项目由公共父 pom 统一管理,不允许随便改父 pom 里的编码配置,那在 IDEA 里通过 Runner VM Options 和 Run Configuration 的 VM options 指定 UTF-8,是目前最不侵入代码库的办法。它的好处是只影响当前开发环境,不改变仓库内容,也不会影响同事。
但如果你是项目负责人,或者有权限调整构建配置,我还是建议把编码声明写进父 pom 或项目 pom。这样才能保证新成员克隆项目后,第一次跑 Maven 就处于正确配置中,不用靠“每人手动改 IDEA 设置”来维护。
我见过太多团队是这样的状态:项目能编译,是因为老成员每个人电脑里都配过了;新成员入职第一天就开始乱码,然后群里有人远程指导一步步改。这种模式的本质是“隐性配置”,非常消耗团队精力。与其这样,不如在 pom 里写死编码,一劳永逸。
最后再说一个我自己的经验。早期我排查乱码时,总喜欢先去翻 IDEA 的设置,其实很多问题的根源不在那里。后来我养成一个习惯:遇到乱码,先写个测试类看 JVM 实际编码,再判断是不是 Maven 进程的问题。一次排查下来,通常 10 分钟就能锁定方向。编码问题看着烦,本质就是“链条上某一环不一致”。只要把源码编码、编译编码、进程编码、控制台展示编码全部统一成 UTF-8,乱码基本就和你无缘了。
希望这篇笔记能帮你少走几次弯路。刚接触这块的朋友,按我第 4 节的清单走一遍,今晚就能睡个安稳觉。