1. 概述
在 Java 开发中,当你尝试声明一个过长的字符串常量(超过 64 KB),编译器会抛出 “constant string too long” 错误。
这问题虽然不常见,但一旦踩坑,编译直接失败,尤其在 Maven 构建时容易暴露。本文将带你定位问题根源,并给出简单粗暴又靠谱的解决方案。
2. 问题复现
我们先来复现这个错误。假设在单元测试中直接声明一个超长字符串:
@Test
public void whenDeclaringTooLongString_thenCompilationError() {
String stringTooLong = "stringstringstring ... 100,000 characters ... string";
assertThat(stringTooLong).isNotEmpty();
}
这里的 stringTooLong
包含了超过 10 万字符的文本。你可以在 GitHub 仓库中找到完整内容(见文末链接),复制进去即可触发错误。
⚠️ 注意:在 IntelliJ 或 Eclipse 等 IDE 中直接运行测试,可能 不会报错。
原因是 IDE 通常做了编译优化或缓存处理,掩盖了真实问题。
但一旦通过命令行构建项目,比如执行:
mvn compile
# 或
mvn test
就会看到类似如下错误:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.058 s
[INFO] Finished at: 2020-03-14T17:56:34+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:testCompile (default-testCompile) on project core-java-strings: Compilation failure
[ERROR] <path to the test class>:[10,32] constant string too long
根本原因
Java 虚拟机规范规定:
✅ 类文件中 CONSTANT_Utf8_info
结构对字符串长度的限制是 2^16 - 1 字节(即 65,535 字节),使用 UTF-8 编码。
如果你的字符串经过 UTF-8 编码后超过这个长度,编译器就直接拒绝,报错“constant string too long”。
3. 解决方案
既然不能把大字符串硬编码在代码里,就得把它“请出去”。以下是两种生产环境常用做法:
✅ 方案一:存为资源文件,运行时读取
将超长字符串保存为一个 .txt
文件,放在 src/test/resources
目录下,例如:
src/test/resources/stringtoolong.txt
然后在测试中读取:
@Test
public void whenStoringInFileTooLongString_thenNoCompilationError() throws IOException {
FileInputStream fis = new FileInputStream("src/test/resources/stringtoolong.txt");
String stringTooLong = IOUtils.toString(fis, "UTF-8");
assertThat(stringTooLong).isNotEmpty();
}
💡 提示:
IOUtils.toString()
来自 Apache Commons IO,也可以用Files.readString(Paths.get(...))
(Java 11+)
✅ 方案二:放入 properties 配置文件
适用于需要参数化管理的场景。创建一个 config.properties
:
stringtoolong=very long string content here...
路径:src/main/resources/config.properties
然后在代码中加载:
@Test
public void whenStoringInPropertiesString_thenNoCompilationError() throws IOException {
try (InputStream input = new FileInputStream("src/main/resources/config.properties")) {
Properties prop = new Properties();
prop.load(input);
String sValue = prop.getProperty("stringtoolong");
assertThat(sValue).isNotEmpty();
}
}
这样,字符串不再参与编译期常量池构建,自然绕过了长度限制。
❌ 不推荐方案:字符串拼接
你可能会想:那我拆成多个字符串拼接总行了吧?
String s = "part1" + "part2" + ...; // 拼几十个?
虽然 JVM 会在编译期做常量折叠,但最终合并后的字符串仍需满足 64KB 限制。而且代码可读性极差,属于“治标不治本”的做法,强烈不推荐。
4. 总结
- ❌ 编译期字符串常量最大不能超过 65,535 字节(UTF-8 编码)
- ⚠️ IDE 可能不会报错,但
mvn compile
会失败,CI/CD 中容易翻车 - ✅ 正确姿势:把超长字符串移到外部文件(
.txt
或.properties
) - ✅ 运行时加载,避免编译期检查
- 🚫 别用字符串拼接硬扛,代码难维护还可能无效
示例代码已托管至 GitHub:https://github.com/baeldung/core-java-modules/tree/master/core-java-string-operations-6