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


原始标题:Fixing “constant string too long” Build Error | Baeldung