indexOf() 是 Java String 类中最常用、最核心的查找方法之一,用于定位字符或子串在字符串中的位置。

方法定义

String 类提供了四个重载的 indexOf() 方法:

// 1. 查找指定字符第一次出现的索引
public int indexOf(int ch)

// 2. 从指定索引开始查找字符第一次出现的索引
public int indexOf(int ch, int fromIndex)

// 3. 查找指定子字符串第一次出现的索引
public int indexOf(String str)

// 4. 从指定索引开始查找子字符串第一次出现的索引
public int indexOf(String str, int fromIndex)

返回值:

  • 找到时返回首次出现的索引位置(从 0 开始)。
  • 未找到时返回 -1

参数说明:

  • ch:要查找的字符(int 类型,兼容 char)。
  • str:要查找的子字符串。
  • fromIndex:开始搜索的起始索引(包含该位置)。若为负数,按 0 处理。

功能说明

indexOf() 的核心功能是在字符串中搜索目标字符或子串,并返回其第一次出现的位置

  • 搜索方向: 总是从左到右(从前向后)扫描。
  • 区分大小写: 搜索是区分大小写的。
  • 返回 -1 表示未找到匹配项,这是判断“不存在”的关键依据。
  • 起始索引: fromIndex 参数允许跳过字符串前部,从指定位置开始搜索,常用于查找第二次及以后的出现位置。

示例代码

基础用法

public class IndexOfExample {
    public static void main(String[] args) {
        String text = "Hello, Java Programming!";

        // 查找字符
        System.out.println(text.indexOf('a'));        // 输出: 7 (第一个 'a')
        System.out.println(text.indexOf('z'));        // 输出: -1 (未找到)

        // 从指定位置开始查找字符
        System.out.println(text.indexOf('a', 8));     // 输出: 14 (第二个 'a')

        // 查找子字符串
        System.out.println(text.indexOf("Java"));     // 输出: 7
        System.out.println(text.indexOf("java"));     // 输出: -1 (区分大小写)

        // 从指定位置开始查找子串
        System.out.println(text.indexOf("gram", 15)); // 输出: 20
    }
}

查找所有出现位置

public static void findAllOccurrences(String text, String target) {
    int index = text.indexOf(target);
    while (index != -1) {
        System.out.println("Found '" + target + "' at index: " + index);
        index = text.indexOf(target, index + 1); // 从下一个位置继续查找
    }
}

// 调用
findAllOccurrences("banana", "ana");
// 输出:
// Found 'ana' at index: 1
// Found 'ana' at index: 3

判断子串是否存在(推荐方式)

String sentence = "I love Java and JavaScript";
boolean containsJava = sentence.indexOf("Java") != -1;
System.out.println(containsJava); // true

使用技巧

  1. 快速判断存在性
    使用 indexOf(str) != -1 是判断子串是否存在的最高效方式之一,比 contains() 在某些 JDK 版本中略快(但 contains() 更语义清晰)。

  2. 查找第 N 次出现
    结合循环和 fromIndex 参数,轻松实现查找第 2、第 3 次出现的位置。

  3. 定位分隔符位置
    常用于解析字符串,如查找第一个逗号、等号、冒号等。

    String config = "name=John,age=30";
    int eqIndex = config.indexOf('=');
    String value = config.substring(eqIndex + 1, config.indexOf(',', eqIndex));
    
  4. lastIndexOf() 配合
    lastIndexOf() 从后往前找,两者结合可处理复杂字符串提取。

    String path = "/home/user/docs/file.txt";
    int lastSlash = path.lastIndexOf('/');
    String fileName = path.substring(lastSlash + 1); // "file.txt"
    
  5. 链式调用定位边界
    在解析协议或格式化文本时非常有用。

    String html = "<title>My Page</title>";
    int start = html.indexOf("<title>") + 7;
    int end = html.indexOf("</title>");
    String title = html.substring(start, end);
    

常见错误

  1. 忽略返回值 -1

    String str = "Hello";
    int pos = str.indexOf("World");
    // 错误:直接使用 pos 而不检查
    char nextChar = str.charAt(pos + 1); // 抛出 StringIndexOutOfBoundsException
    

    纠正:

    if (pos != -1 && pos + 1 < str.length()) {
        char nextChar = str.charAt(pos + 1);
    }
    
  2. 混淆大小写

    "Java".indexOf("java") // 返回 -1,因为区分大小写
    

    纠正: 使用 toLowerCase() 预处理或 indexOf() 无法解决,需用正则或 Pattern

  3. fromIndex 越界或负数

    "abc".indexOf('a', 10);  // 不报错,返回 -1
    "abc".indexOf('a', -5);  // 不报错,按 0 处理,返回 0
    

    虽然不会抛异常,但逻辑可能出错。

  4. 空字符串查找

    "abc".indexOf("") // 返回 0,因为空串在任何位置都“匹配”
    "abc".indexOf("", 2) // 返回 2
    

注意事项

  1. 性能为 O(n)
    最坏情况下需要扫描整个字符串,时间复杂度为 O(n)。对超长字符串频繁调用需谨慎。

  2. 区分大小写
    如需忽略大小写,应先统一转换:

    String lowerText = text.toLowerCase();
    int pos = lowerText.indexOf(target.toLowerCase());
    
  3. 空指针安全
    调用对象为 null 时会抛出 NullPointerException

    String s = null;
    s.indexOf("a"); // NullPointerException
    
  4. 空字符串行为
    查找空字符串 "" 总是返回 fromIndex(或 0),需根据业务判断是否合理。

  5. 字符编码
    对 Unicode 字符(如 emoji)查找时,int ch 可正确处理代理对(通过码点),但 String 参数需注意编码一致性。


最佳实践与性能优化

  1. 优先使用 indexOf() 判断存在性
    contains() 略高效(JDK 8-17 中 contains() 内部调用 indexOf(),语义更清晰)。

  2. 避免在循环中重复调用
    如果需多次查找同一模式,考虑使用 PatternMatcher(尤其复杂模式)或缓存结果。

  3. 结合 StringBuilder 使用时注意
    StringBuilder 也提供 indexOf(),适用于可变字符串场景。

  4. 使用 CharSequence 接口提高兼容性
    方法参数可声明为 CharSequence,兼容 StringStringBuilder 等。

  5. 性能敏感场景考虑 Boyer-Moore 等算法
    对固定模式的高频查找,可使用第三方库(如 Apache Commons Lang 的 StringUtils.indexOf() 优化版本)。

  6. 替代方案对比 | 场景 | 推荐方法 | |---|---| | 简单存在判断 | indexOf() != -1contains() | | 忽略大小写 | toLowerCase().indexOf() | | 正则匹配 | Pattern.matcher().find() | | 多次查找同一串 | 缓存 fromIndex 循环 | | 从后往前找 | lastIndexOf() |


总结

String.indexOf() 是 Java 字符串处理的基石方法,掌握其核心要点可大幅提升开发效率与代码健壮性。

核心要点回顾:

  • 返回首次匹配的索引,未找到返回 -1
  • 区分大小写,支持从指定位置开始搜索。
  • 时间复杂度 O(n),适用于大多数查找场景。
  • 必须检查 -1 防止越界错误。
  • lastIndexOf()substring() 配合可实现强大解析功能。

🚀 实践建议:

  • 简单查找用 indexOf(),语义清晰用 contains()
  • 查找多次出现时,用 index = indexOf(target, index + 1) 循环。
  • 避免忽略 -1 导致运行时异常。
  • 性能瓶颈时考虑正则或专用算法。

indexOf() 虽简单,却是字符串处理的“瑞士军刀”。熟练掌握其用法,是每个 Java 开发者的必备技能。