一、方法定义

public synchronized StringBuffer setCharAt(int index, char ch)

参数说明:

  • index:要设置字符的位置索引(从0开始)。
  • ch:要设置的字符值。

返回值:

  • 返回当前 StringBuffer 对象的引用(支持链式调用)。

异常:

  • IndexOutOfBoundsException:如果 index 小于 0 或大于等于当前字符串的长度(length())。

二、功能说明

setCharAt() 方法用于将 StringBuffer 中指定索引位置的字符替换为新的字符。该操作是原地修改,不会创建新的对象。

核心特点:

  • 线程安全:方法被 synchronized 修饰,可在多线程环境中安全调用。
  • 高效修改:直接修改内部字符数组,性能优于替换子串。
  • 支持链式调用:返回 this,可连续调用其他方法。
  • 单字符替换:只能修改一个字符,不能插入或删除。

三、示例代码

示例 1:基本字符替换

StringBuffer sb = new StringBuffer("hello");
sb.setCharAt(0, 'H'); // 将第一个字符 'h' 改为 'H'
System.out.println(sb.toString()); // 输出:Hello

示例 2:修改中间字符

StringBuffer sb = new StringBuffer("Java");
sb.setCharAt(2, 'v'); // 'v' 已是原字符,无变化
sb.setCharAt(1, 'a'); // 将 'a' 改为 'a'(无变化)
sb.setCharAt(3, '!'); // 将 'a' 改为 '!'
System.out.println(sb.toString()); // 输出:Jav!

示例 3:链式调用

StringBuffer sb = new StringBuffer("test");
sb.setCharAt(0, 'T')
  .setCharAt(1, 'E')
  .setCharAt(2, 'S')
  .setCharAt(3, 'T');
System.out.println(sb.toString()); // 输出:TEST

示例 4:异常处理(索引越界)

StringBuffer sb = new StringBuffer("abc");
try {
    sb.setCharAt(5, 'x'); // 索引5超出范围[0,2]
} catch (IndexOutOfBoundsException e) {
    System.out.println("错误:" + e.getMessage());
}

示例 5:修改数字字符串中的某一位

StringBuffer sb = new StringBuffer("12345");
sb.setCharAt(2, '0'); // 将 '3' 改为 '0'
System.out.println(sb.toString()); // 输出:12045

四、使用技巧

技巧 1:实现字符串“加密”或掩码

StringBuffer sb = new StringBuffer("password123");
for (int i = 0; i < sb.length() - 4; i++) {
    sb.setCharAt(i, '*');
}
System.out.println(sb.toString()); // 输出:*******123

技巧 2:反转字符串(配合循环)

StringBuffer sb = new StringBuffer("reverse");
int n = sb.length();
for (int i = 0; i < n / 2; i++) {
    char temp = sb.charAt(i);
    sb.setCharAt(i, sb.charAt(n - 1 - i));
    sb.setCharAt(n - 1 - i, temp);
}
System.out.println(sb.toString()); // 输出:esrever

技巧 3:校验并修改特定字符

StringBuffer sb = new StringBuffer("user@email");
// 将非法字符 '@' 改为 '.'
for (int i = 0; i < sb.length(); i++) {
    if (sb.charAt(i) == '@') {
        sb.setCharAt(i, '.');
    }
}
System.out.println(sb.toString()); // 输出:user.email

五、常见错误

❌ 错误 1:索引越界

StringBuffer sb = new StringBuffer("a");
sb.setCharAt(1, 'b'); // 抛出 IndexOutOfBoundsException

原因:有效索引为 [0, length()-1],即只有 0

❌ 错误 2:负索引

sb.setCharAt(-1, 'x'); // 直接抛出异常

❌ 错误 3:空 StringBuffer 调用

StringBuffer sb = new StringBuffer();
sb.setCharAt(0, 'a'); // 抛出异常,长度为0

六、注意事项

  1. 索引从0开始,最大有效索引为 length() - 1
  2. 不能用于插入字符:目标位置必须已存在字符。
  3. 线程安全:多线程可安全调用,但性能低于 StringBuilder
  4. ⚠️ 性能良好:直接操作内部数组,时间复杂度 O(1)。
  5. 字符值无限制ch 可以是任意 char 值,包括 Unicode 字符。

七、最佳实践

✅ 实践 1:预检查长度再修改

StringBuffer sb = new StringBuffer("data");
int index = 2;
if (index >= 0 && index < sb.length()) {
    sb.setCharAt(index, 'X');
} else {
    System.out.println("索引无效");
}

✅ 实践 2:在多线程中安全修改

// 多个线程可安全修改不同位置
Thread t1 = () -> sb.setCharAt(0, 'A');
Thread t2 = () -> sb.setCharAt(1, 'B');
t1.start(); t2.start();

✅ 实践 3:避免在循环中频繁修改(高并发)

  • 虽然 setCharAt 是 O(1),但 synchronized 可能成为瓶颈。
  • 高并发场景可考虑先用 StringBuilder 处理,再赋值。

八、性能优化建议

  1. 单线程优先使用 StringBuilder

    // 单线程场景
    StringBuilder sb = new StringBuilder("text");
    sb.setCharAt(0, 'T'); // 更快,无同步开销
    
  2. 批量修改时考虑 replace()

    • 若需修改连续多个字符,使用 replace(start, end, str) 更高效。
  3. 预设容量减少扩容

    StringBuffer sb = new StringBuffer(100); // 预分配
    

总结

项目 说明
核心功能 安全修改指定位置的单个字符
关键特性 线程安全、原地修改、O(1) 时间复杂度
适用场景 动态文本微调、掩码处理、字符校验
使用技巧 可用于掩码、反转、条件替换
性能提示 单线程用 StringBuilder 更优,避免越界
常见错误 索引越界、空对象调用

💡 一句话总结StringBuffer.setCharAt(index, ch) 是一个线程安全的单字符替换方法,适用于多线程环境下的精确字符修改。注意索引边界,单线程场景推荐使用 StringBuilder.setCharAt() 以获得更高性能。