Java中用+拼接字符串需注意:编译期字面量相加被优化为常量,含变量时每次均创建StringBuilder和String对象;循环中滥用会导致O(n²)复杂度和大量临时对象;仅在≤3项且无循环时安全使用。

用 + 拼接字符串要注意什么
Java里最直观的拼接方式是用 +,但它在不同场景下行为差异很大。编译期能确定的字符串字面量相加(比如 "a" + "b")会被JVM直接优化成常量 "ab";但只要涉及变量(哪怕只是 String s = "a"; s + "b"),就会在运行时生成 StringBuilder 实例来完成拼接。
常见错误是循环中滥用 +:
String result = "";
for (String item : list) {
result += item; // 每次都新建 StringBuilder → toString() → 新 String
}
这会导致 O(n²) 时间复杂度和大量临时对象。如果 list 有 10000 个元素,实际会创建约 10000 个 StringBuilder 和等量的 String 对象。
- 仅在拼接项极少(≤3)、且不含循环时放心用
+ - 含变量或不确定长度时,别信“现代JVM已优化”的说法——它只优化字节码层面的常量折叠,不改变语义上的对象创建逻辑
-
javac编译后反编译看字节码,就能确认是否真用了StringBuilder
StringBuilder 和 StringBuffer 怎么选
两者都提供 append()、toString() 等方法,核心区别在是否同步:StringBuffer 所有 public 方法都加了 synchronized,而 StringBuilder 完全不加锁。
立即学习“Java免费学习笔记(深入)”;
除非你明确需要多线程共享同一个拼接器(极少见),否则一律用 StringBuilder。性能差距在高并发场景下可达 2–5 倍。
- 单线程拼接:无条件选
StringBuilder - 初始化容量很重要——默认构造函数分配 16 字符缓冲区,若预估最终长度为 1000,应写
new StringBuilder(1024),避免多次数组扩容 -
StringBuffer基本只存在于遗留代码或教学示例中,新项目可视为已淘汰
Java 8+ 的 String.join() 适合什么场景
String.join() 是专为“用分隔符连接多个字符串”设计的快捷方法,底层仍用 StringBuilder,但封装了边界处理逻辑。
它只接受一个分隔符和一个 Iterable(如 List 或数组),不支持混合类型拼接(比如字符串 + 数字)。
String joined = String.join(", ", Arrays.asList("a", "b", "c")); // → "a, b, c"
String joined2 = String.join("-", "x", "y", "z"); // Java 11+ 支持可变参数
- 当目标是“把一堆字符串用固定符号串起来”,优先用
String.join(),语义清晰且不易出错 - 若需对每个元素做转换(如
item.toUpperCase()),先用stream().map()处理再 join,别在循环里手动拼 - 注意
null元素:传入null会抛NullPointerException,需提前过滤或替换
Java 15+ 的 String.formatted() 和 MessageFormat 的取舍
String.formatted() 是对 String.format() 的语法糖,两者都基于 java.util.Formatter,适用于带占位符的模板拼接(如日志、SQL 构造)。但它不是通用拼接工具。
典型误用是拿它替代 StringBuilder 做纯连接:"%s%s%s".formatted(a, b, c) —— 这会触发格式化解析、类型检查、宽度计算等开销,比直接 new StringBuilder().append(a).append(b).append(c) 慢 3–10 倍。
- 仅在需要类型转换(
%d、%02x)、对齐(%-10s)或本地化(Locale)时用formatted() - 普通字符串连接不要用它,尤其高频调用路径(如网络请求响应组装)
-
MessageFormat更重,支持复数、日期模式等,但解析开销更大,仅用于国际化资源绑定
真正复杂的拼接逻辑(比如嵌套结构、条件分支),别硬凑字符串 API,该上模板引擎(如 StringTemplate)就上,别拿 StringBuilder 往死里套。










