一、方法定义
public void ensureCapacity(int minimumCapacity)
参数说明:
minimumCapacity
:期望的最小容量(字符数),即内部字符数组的最小长度。
返回值:
- 无(
void
)。
异常:
- 无显式异常抛出,但若传入负数,行为未定义(通常被忽略或视为0)。
二、功能说明
ensureCapacity()
方法用于确保 StringBuffer
的内部缓冲区(字符数组)具有至少 minimumCapacity
的容量。如果当前容量小于该值,StringBuffer
会自动扩容(通常是当前容量的2倍 + 2,或直接扩容到 minimumCapacity
,具体实现可能因JDK版本而异)。
核心目的:
- 避免频繁扩容:提前分配足够空间,减少在
append()
、insert()
等操作时因容量不足而触发的数组复制开销。 - 性能优化:在已知最终字符串长度时,预分配空间可显著提升性能。
关键特点:
- ✅ 线程安全:方法被
synchronized
修饰,多线程调用安全。 - ✅ 容量只增不减:此方法只会增加容量,不会缩小。
- ✅ 非强制精确匹配:扩容后的容量可能大于
minimumCapacity
(如按增长策略)。 - ✅ 不影响长度:调用后
length()
不变,仅改变capacity()
。
三、示例代码
示例 1:基本用法
StringBuffer sb = new StringBuffer();
System.out.println("初始容量: " + sb.capacity()); // 通常为16
sb.ensureCapacity(50);
System.out.println("确保50后容量: " + sb.capacity()); // >=50,如50或66
示例 2:容量已足够时无操作
StringBuffer sb = new StringBuffer(100); // 初始容量100
sb.ensureCapacity(30); // 当前容量100 > 30,无需扩容
System.out.println("容量: " + sb.capacity()); // 仍为100
示例 3:与 append() 配合使用(性能优化)
StringBuffer sb = new StringBuffer();
// 预估最终长度约为1000
sb.ensureCapacity(1000);
// 执行大量 append 操作
for (int i = 0; i < 500; i++) {
sb.append("data");
}
// 由于已预分配,避免了中间多次扩容
System.out.println("最终长度: " + sb.length()); // 2000
System.out.println("最终容量: " + sb.capacity()); // >=1000
示例 4:观察扩容行为
StringBuffer sb = new StringBuffer();
System.out.println("初始: " + sb.capacity()); // 16
sb.ensureCapacity(20);
System.out.println("ensure 20: " + sb.capacity()); // 可能是34 (16*2+2)
sb.ensureCapacity(100);
System.out.println("ensure 100: " + sb.capacity()); // >=100
四、使用技巧
技巧 1:结合已知数据量预分配
// 处理大量字符串拼接
int expectedSize = estimatedCount * averageLengthPerItem;
StringBuffer sb = new StringBuffer();
sb.ensureCapacity(expectedSize);
技巧 2:在循环前调用
StringBuffer sb = new StringBuffer();
// 在循环前确保足够容量
sb.ensureCapacity(estimatedTotalLength);
for (String item : largeList) {
sb.append(item).append(",");
}
技巧 3:用于 StringBuilder 的通用优化策略
虽然本节讲 StringBuffer
,但 StringBuilder
也有相同方法,优化思路一致。
五、常见错误
❌ 错误 1:混淆 capacity() 与 length()
StringBuffer sb = new StringBuffer();
sb.ensureCapacity(100);
// 错误:认为此时可以访问索引99
// sb.setCharAt(0, 'a'); // 会抛异常!因为 length() 仍为0
正解:
ensureCapacity
只分配空间,不改变字符串长度。要修改内容需用append()
等。
❌ 错误 2:传入负数
sb.ensureCapacity(-1); // 行为未定义,应避免
❌ 错误 3:期望精确容量
sb.ensureCapacity(50);
int cap = sb.capacity();
// cap 可能是 50, 66, 70 等,不一定是50
六、注意事项
- ✅ 仅保证最小容量:实际容量可能更大。
- ✅ 扩容开销:若触发扩容,需复制原数组,应尽量在早期调用。
- ⚠️ 非实时性:调用后不一定立即扩容,仅当当前容量不足时才扩容。
- ✅ 线程安全:多线程可安全调用,但高并发下可能竞争锁。
- 📏 默认容量:
new StringBuffer()
默认容量为16。
七、最佳实践
✅ 实践 1:预估并预分配
// 好:已知大致长度
StringBuffer sb = new StringBuffer();
sb.ensureCapacity(1024); // 预分配1KB空间
✅ 实践 2:避免在循环中调用
// ❌ 低效
for (int i = 0; i < 1000; i++) {
sb.ensureCapacity(i * 10); // 每次都检查,浪费
sb.append("...");
}
// ✅ 高效
sb.ensureCapacity(10000); // 一次预分配
for (int i = 0; i < 1000; i++) {
sb.append("...");
}
✅ 实践 3:与构造函数结合
// 更简洁的方式
StringBuffer sb = new StringBuffer(1024); // 直接指定初始容量
// 等价于 new StringBuffer().ensureCapacity(1024);
八、性能优化建议
- 尽早调用:在
append()
大量数据前调用,避免中间扩容。 - 合理预估:过高预估浪费内存,过低仍需扩容。
- 单线程用 StringBuilder:
// 单线程场景性能更优 StringBuilder sb = new StringBuilder(1000);
- 监控实际容量:使用
capacity()
方法检查是否达到预期。
总结
项目 | 说明 |
---|---|
核心功能 | 确保内部缓冲区具有最小容量,避免频繁扩容 |
关键特性 | 线程安全、只增不减、容量 >= minimumCapacity |
适用场景 | 大量字符串拼接前的性能优化 |
使用技巧 | 结合预估长度、在循环前调用 |
常见错误 | 混淆 capacity 与 length、传入负数 |
性能提示 | 尽早调用、合理预估、单线程优先 StringBuilder |
💡 一句话总结:
StringBuffer.ensureCapacity(minCapacity)
是一个重要的性能优化方法,用于预先分配足够的内部缓冲空间,减少append
操作时的数组复制开销。它线程安全,但仅改变容量不影响长度。