一、方法定义

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

六、注意事项

  1. 仅保证最小容量:实际容量可能更大。
  2. 扩容开销:若触发扩容,需复制原数组,应尽量在早期调用。
  3. ⚠️ 非实时性:调用后不一定立即扩容,仅当当前容量不足时才扩容。
  4. 线程安全:多线程可安全调用,但高并发下可能竞争锁。
  5. 📏 默认容量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);

八、性能优化建议

  1. 尽早调用:在 append() 大量数据前调用,避免中间扩容。
  2. 合理预估:过高预估浪费内存,过低仍需扩容。
  3. 单线程用 StringBuilder
    // 单线程场景性能更优
    StringBuilder sb = new StringBuilder(1000);
    
  4. 监控实际容量:使用 capacity() 方法检查是否达到预期。

总结

项目 说明
核心功能 确保内部缓冲区具有最小容量,避免频繁扩容
关键特性 线程安全、只增不减、容量 >= minimumCapacity
适用场景 大量字符串拼接前的性能优化
使用技巧 结合预估长度、在循环前调用
常见错误 混淆 capacity 与 length、传入负数
性能提示 尽早调用、合理预估、单线程优先 StringBuilder

💡 一句话总结StringBuffer.ensureCapacity(minCapacity) 是一个重要的性能优化方法,用于预先分配足够的内部缓冲空间,减少 append 操作时的数组复制开销。它线程安全,但仅改变容量不影响长度。