StringBuffer 类提供了 indexOf()lastIndexOf() 方法,用于在可变字符序列中搜索子字符串的位置,是字符串查找操作的核心工具。


一、方法定义

1. indexOf() 方法

public synchronized int indexOf(String str)
public synchronized int indexOf(String str, int fromIndex)

返回值:首次出现的索引位置(从 0 开始),未找到返回 -1
参数

  • str:要搜索的子字符串
  • fromIndex:开始搜索的索引位置(包含)

2. lastIndexOf() 方法

public synchronized int lastIndexOf(String str)
public synchronized int lastIndexOf(String str, int fromIndex)

返回值:最后一次出现的索引位置,未找到返回 -1
参数

  • str:要搜索的子字符串
  • fromIndex反向搜索的起始位置(从该位置向前查找)

⚠️ 所有方法均为 synchronized线程安全


二、功能说明

方法 功能
indexOf(str) 从头开始查找 str 第一次出现的位置
indexOf(str, fromIndex) 从指定位置开始向后查找第一次出现的位置
lastIndexOf(str) 从末尾开始查找 str 最后一次出现的位置
lastIndexOf(str, fromIndex) 从指定位置开始向前查找最后一次出现的位置

🔍 搜索方向

  • indexOf:从左到右(正向)
  • lastIndexOf:从右到左(反向)

三、示例代码

示例 1:基础查找

StringBuffer sb = new StringBuffer("Hello World, Hello Java");

// 查找第一次出现的位置
int first = sb.indexOf("Hello");        // 结果: 0
int world = sb.indexOf("World");        // 结果: 6

// 查找最后一次出现的位置
int last = sb.lastIndexOf("Hello");     // 结果: 13

示例 2:指定起始位置查找

StringBuffer sb = new StringBuffer("a-b-c-d-e");

// 从索引 3 开始查找第一个 '-'
int pos1 = sb.indexOf("-", 3);          // 结果: 4

// 从索引 6 开始向前查找最后一个 '-'
int pos2 = sb.lastIndexOf("-", 6);      // 结果: 4

示例 3:lastIndexOf 的反向搜索特性

StringBuffer sb = new StringBuffer("12-34-56-78");

// 从索引 8 开始向前查找 '-'
int pos = sb.lastIndexOf("-", 8);       // 结果: 6(不是 10)

// 解释:只搜索 [0,8] 范围内的最后一次出现

示例 4:未找到的情况

StringBuffer sb = new StringBuffer("Java");
int notFound1 = sb.indexOf("Python");       // 结果: -1
int notFound2 = sb.lastIndexOf("Python");   // 结果: -1

示例 5:查找单个字符

StringBuffer sb = new StringBuffer("programming");
int pos = sb.indexOf("a");                  // 结果: 3
int lastPos = sb.lastIndexOf("r");          // 结果: 9

示例 6:链式操作示例

StringBuffer sb = new StringBuffer("user@example.com");

// 提取 @ 之前的内容
int atPos = sb.indexOf("@");
if (atPos != -1) {
    String username = sb.substring(0, atPos);
    System.out.println(username); // 输出: user
}

四、使用技巧

技巧 1:检查字符串是否包含子串

boolean contains = sb.indexOf("target") != -1;

技巧 2:统计子字符串出现次数

public static int countOccurrences(StringBuffer sb, String target) {
    int count = 0, index = 0;
    while ((index = sb.indexOf(target, index)) != -1) {
        count++;
        index += target.length(); // 移动到下一次搜索起点
    }
    return count;
}

技巧 3:查找文件扩展名位置

StringBuffer filename = new StringBuffer("document.pdf");
int dotPos = filename.lastIndexOf(".");
if (dotPos != -1) {
    String ext = filename.substring(dotPos + 1);
    System.out.println("扩展名: " + ext); // 输出: pdf
}

技巧 4:提取路径中的文件名

StringBuffer path = new StringBuffer("/home/user/docs/file.txt");
int lastSlash = path.lastIndexOf("/");
if (lastSlash != -1) {
    String filename = path.substring(lastSlash + 1);
    System.out.println(filename); // 输出: file.txt
}

五、常见错误

错误 代码示例 说明
搜索 null 字符串 sb.indexOf(null) 抛出 NullPointerException
索引越界 sb.indexOf("a", -1)sb.indexOf("a", sb.length()+1) fromIndex 超出范围时,indexOf 返回 -1,lastIndexOf 可能返回错误结果
误解 lastIndexOf(fromIndex) sb.lastIndexOf("a", 100) fromIndex 超过长度时,从末尾开始搜索

错误示例

StringBuffer sb = new StringBuffer("test");
int pos = sb.indexOf(null); // 抛出 NullPointerException

六、注意事项

  1. 线程安全:所有方法均为 synchronized
  2. 🔄 不修改原对象:查找操作不会改变 StringBuffer 内容
  3. 🔍 完全匹配:区分大小写,要求完全匹配
  4. 📏 索引范围
    • fromIndex 应在 [0, length()] 范围内
    • 超出范围时通常返回 -1
  5. 🚫 不支持正则表达式:只能进行字面量字符串匹配
  6. 🌍 Unicode 支持:正确处理多字节字符

七、最佳实践与性能优化

✅ 最佳实践

场景 推荐做法
简单存在性检查 使用 indexOf(str) != -1
提取文件名/扩展名 使用 lastIndexOf()
多次查找 复用查找逻辑
单线程环境 考虑先转为 String 再操作(若不再修改)

🚀 性能优化建议

  1. 单线程环境下考虑转换为 String

    // 如果后续只读操作多,可转换为 String 提升性能
    String str = sb.toString();
    int pos = str.indexOf("target"); // StringBuilder/String 更快
    
  2. 避免在循环中重复创建 StringBuffer

    // 推荐:复用对象
    StringBuffer sb = new StringBuffer("template");
    for (String keyword : keywords) {
        int pos = sb.indexOf(keyword); // 直接查找
        if (pos != -1) process(pos);
    }
    
  3. 合理使用 fromIndex 避免重复搜索

    // 查找所有匹配项时,从上次位置后开始
    int index = 0;
    while ((index = sb.indexOf("and", index)) != -1) {
        System.out.println("Found at: " + index);
        index += 3; // 移动到 "and" 之后
    }
    
  4. 对于频繁查找场景,考虑使用更高级的数据结构

    • 如需频繁模式匹配,考虑使用 Pattern/Matcher
    • 大量文本处理可考虑专用文本处理库

八、indexOf() vs lastIndexOf() 对比

特性 indexOf() lastIndexOf()
搜索方向 从左到右 从右到左
fromIndex 含义 起始搜索位置 反向搜索的起点
典型用途 首次出现、前缀查找 最后出现、后缀提取
性能 相同量级 O(n) 相同量级 O(n)

九、总结

要点 说明
✅ 核心功能 在 StringBuffer 中查找子字符串位置
✅ 线程安全 所有方法均为 synchronized
✅ 返回值 找到返回索引(≥0),未找到返回 -1
✅ 方法类型 indexOf:正向查找,lastIndexOf:反向查找
⚠️ 常见错误 搜索 null、误解 fromIndex 含义
🚀 性能建议 单线程可考虑转为 String,避免重复搜索
💡 最佳实践 用于存在性检查、位置定位、字符串解析等

📌 一句话总结

StringBuffer.indexOf()lastIndexOf() 是线程安全的字符串查找利器,分别用于定位子串的首次和最后一次出现位置。记住 lastIndexOf(fromIndex) 是从指定位置向前搜索,且所有查找操作都不修改原对象。在单线程高性能场景中,可考虑转换为 String 或使用 StringBuilder 替代。