indexof 找不到字符时返回 -1 而非抛异常;常见错误是直接将 indexof 结果传给 charat 导致索引越界;使用前须检查返回值 ≥ 0;重载方法包括查字符、子串及指定起始位置;区分大小写;charat 仅按索引取值,越界必抛 stringindexoutofboundsexception。

indexOf 找不到字符时返回 -1,不是抛异常
很多人以为 indexOf 找不到会像 charAt 那样报 StringIndexOutOfBoundsException,其实不会——它安静地返回 -1。这个设计本意是方便判断“是否存在”,但恰恰因为不报错,容易埋下空指针或逻辑跳过的问题。
常见错误现象:用 indexOf 查找后直接传给 charAt,比如 str.charAt(str.indexOf('x')),当字符不存在时,就拿 -1 去索引,立刻崩。
- 使用前务必检查返回值是否 ≥ 0:
int pos = str.indexOf('a'); if (pos >= 0) { ... } -
indexOf有多个重载:查单个char(indexOf(int ch))、查子串(indexOf(String str))、从指定位置开始查(indexOf(char, fromIndex)),注意参数类型别传错 - 区分大小写:
"Abc".indexOf('a')返回-1,不是0
charAt 越界只看长度,不关心内容是否存在
charAt 的职责非常单纯:按索引取字符。它不管你要的索引对应的是不是目标字符,也不管这个位置有没有意义——只要越界(index = length()),立刻抛 StringIndexOutOfBoundsException。
典型误用场景:循环遍历字符串时用 for (int i = 0; i ,多跑一次导致 <code>i == str.length() 时调用 charAt 必崩。
立即学习“Java免费学习笔记(深入)”;
- 合法索引范围是
0到str.length() - 1,闭区间 - 不要假设
indexOf和charAt可以混用而不出错,它们的契约完全不同 - 如果只是想确认某个位置的字符是不是目标值,直接用
str.charAt(i) == 'x'更直观,比先indexOf再charAt少一层间接
性能差异:indexOf 是线性扫描,charAt 是 O(1) 随机访问
在字符串很长、查找频繁的场景下,两者的开销差别明显。charAt 底层就是数组索引,几乎无成本;而 indexOf 每次都要从头或指定位置往后逐个比对,最坏 O(n)。
比如要判断一个长日志字符串里是否包含某个关键字,用 indexOf != -1 是合理选择;但如果已经知道大概位置(比如第 1000 个字符附近),硬要写成 str.indexOf('x', 990),不如直接 str.charAt(995) == 'x' 来得快又稳。
- 反复查同一字符串的多个固定位置?优先用
charAt - 不确定位置、需要定位首次出现点?用
indexOf,但记得加边界检查 - Java 9+ 字符串内部用
byte[]存储(紧凑字符串),对 ASCII 字符不影响charAt性能,但indexOf的比较逻辑仍需逐字节读取
中文和 emoji 场景下 charAt 可能“取半”
Java 的 char 是 UTF-16 编码单位,不是 Unicode 字符。遇到增补字符(如大多数 emoji、部分汉字),一个字符实际占两个 char(即一个代理对)。这时 charAt(i) 只能拿到高代理或低代理,单独看是无效值。
现象:对字符串 "??"(程序员 emoji)调用 charAt(0) 得到 '\ud83d',charAt(1) 得到 '\udcfc',都不是完整字符;length() 返回 2,但真实字符数是 1。
- 需要准确计数或遍历时,改用
str.codePointCount(0, str.length())和str.charAt(i)+Character.isSurrogatePair判断 - 更稳妥的做法是用
str.codePoints().forEach(...)流式处理 Unicode 字符 -
indexOf在这种场景下行为一致:它也按 UTF-16 码元匹配,所以查"??".indexOf('\ud83d')会命中,但这通常不是你想要的语义
事情说清了就结束。真正麻烦的从来不是方法怎么写,而是你以为它在干一件事,其实它在干另一件。










