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
六、注意事项
- ✅ 线程安全:所有方法均为
synchronized
- 🔄 不修改原对象:查找操作不会改变
StringBuffer
内容 - 🔍 完全匹配:区分大小写,要求完全匹配
- 📏 索引范围:
fromIndex
应在[0, length()]
范围内- 超出范围时通常返回
-1
- 🚫 不支持正则表达式:只能进行字面量字符串匹配
- 🌍 Unicode 支持:正确处理多字节字符
七、最佳实践与性能优化
✅ 最佳实践
场景 | 推荐做法 |
---|---|
简单存在性检查 | 使用 indexOf(str) != -1 |
提取文件名/扩展名 | 使用 lastIndexOf() |
多次查找 | 复用查找逻辑 |
单线程环境 | 考虑先转为 String 再操作(若不再修改) |
🚀 性能优化建议
单线程环境下考虑转换为 String
// 如果后续只读操作多,可转换为 String 提升性能 String str = sb.toString(); int pos = str.indexOf("target"); // StringBuilder/String 更快
避免在循环中重复创建 StringBuffer
// 推荐:复用对象 StringBuffer sb = new StringBuffer("template"); for (String keyword : keywords) { int pos = sb.indexOf(keyword); // 直接查找 if (pos != -1) process(pos); }
合理使用
fromIndex
避免重复搜索// 查找所有匹配项时,从上次位置后开始 int index = 0; while ((index = sb.indexOf("and", index)) != -1) { System.out.println("Found at: " + index); index += 3; // 移动到 "and" 之后 }
对于频繁查找场景,考虑使用更高级的数据结构
- 如需频繁模式匹配,考虑使用
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
替代。