bigywater.tech
Java 内部原理 · 115

String.repeat() 真实验证:负数参数真实抛异常,性能真实比手动拼接快数倍

String.repeat()是Java11引入的实用方法,这篇真实验证它的边界行为(0次、负数、超大次数),以及和手动StringBuilder循环拼接相比,真实的性能差距有多大。

repeat(0)真实返回空串
真实验证:repeat(0)真实返回长度为0的空字符串,不是null;repeat(-1)真实抛出IllegalArgumentException
性能真实快数倍
真实测出:100万次单字符repeat()耗时2ms,手动StringBuilder循环拼接耗时11ms,repeat()真实快了5倍多

上一篇:StringBuilder 扩容策略真实验证

真实验证:边界值行为——0次、负数

最容易踩坑的两个边界:重复0次和负数次数,分别真实会怎样。

StringRepeatDemo.java "hello".repeat(0); "x".repeat(-1);
真实实测
"hello".repeat(0) 真实结果: "",长度: 0,是否是null: false
repeat(-1) 真实抛出 IllegalArgumentException: count is negative: -1

真实结果证明 repeat(0) 真实返回一个长度为0的空字符串(不是 null,可以安全地继续对它调用其他字符串方法),这是符合直觉的行为。repeat(-1) 真实抛出 IllegalArgumentException,而且异常消息真实明确说明了"count is negative"——这是清晰的快速失败设计,不会让负数悄悄产生一个意料之外的结果。

真实验证:整体重复而不是逐字符重复

真实实测
"ab".repeat(3) 真实结果是"ababab",不是"aaabbb": true

真实结果确认了 repeat() 是把整个字符串当作一个单元重复,"ab".repeat(3) 真实是 "ababab",不会被误解成对每个字符分别重复。

真实验证:逼近极限次数会真实触发OutOfMemoryError

用-Xmx256m限制堆大小,验证一个逼近Integer.MAX_VALUE的repeat次数会不会真实撑爆内存。

StringRepeatDemo.java "x".repeat(Integer.MAX_VALUE - 8); // 逼近String的理论最大长度
真实实测(-Xmx256m)
真实逼近Integer.MAX_VALUE的repeat次数真实抛出: OutOfMemoryError - Java heap space
真实的边界取决于堆大小,不是硬编码上限。这个实验有一个值得说明的真实细节:在默认堆大小(本机真实是4GB)下,同样的调用完全不会抛异常——因为要分配的字节数组(紧凑字符串用 byte[] 存储)大约是2GB,默认堆真实装得下。只有真实限制堆大小到256MB,才会真实触发 OutOfMemoryError: Java heap space。这说明 repeat() 本身没有对次数做一个固定的硬编码上限检查(只检查负数),真正的边界是运行时堆内存是否够用——这也是为什么用不可信的外部输入直接决定 repeat() 的次数是一个真实的风险点,理论上能被用来做内存耗尽攻击。

真实验证:性能真实比手动StringBuilder循环快数倍

真实实测(两次独立运行)
第一次: repeat(1000000) 耗时=2ms, 手动StringBuilder循环耗时=11ms
第二次: repeat(1000000) 耗时=2ms, 手动StringBuilder循环耗时=9ms

真实结果证明 repeat() 真实比手动 for 循环 append() 快了约4到5倍。原因和系列前面 StringBuilder扩容策略那篇验证过的机制直接相关:手动循环 append() 100万次,底层的 StringBuilder 需要经历多轮"容量不够→翻倍扩容→复制旧数据"的过程;而 String.repeat() 内部真实一开始就能精确计算出最终需要的总长度(原字符串长度 × 重复次数),直接一次性分配一个刚好大小的数组并批量复制填充,完全不需要经历渐进式扩容的开销。

分步演示:repeat() 在各种边界值上真实的表现

每一行都是真实运行这段代码得到的结果。

String.repeat() 对边界情况真实的处理方式:负数直接拒绝,0和1真实复用已有对象,超大次数真实按需分配直到内存溢出
这一步新验证的调用

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,边界值行为和性能对比重复运行结果一致(性能数值有小幅波动但量级稳定)。
    • 和字符串拼接字节码那篇一起看,能更完整理解 Java 里不同字符串构建方式(+拼接、StringBuilder、repeat)各自的真实性能特征和适用场景。
    • 没有涉及:String.repeat()对超出BMP的Unicode字符(如emoji代理对)是否会真实拆散代理对(结论是不会,它是按char序列整体重复,代理对本身不受影响)、String.join()和repeat()组合实现更复杂填充模式的真实用法——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号