String.contains遇到空字符串

本文深入探讨了Java中String类的contains()和indexOf()方法的内部实现,揭示了它们在处理空字符串时的特殊逻辑。当调用contains()时,返回值为true并不一定表示字符串中包含内容,可能是因为空字符串的indexOf()返回值为0。此外,还总结了indexOf()方法在不同情况下的返回值特点,包括开始下标超出范围和目标字符串长度为0的情况。

源于一次bug,得知:String.contains("") 的返回值为 true

不得其解,追查了一下源代码:

# 包含关系的判断是用字符串首次出现位置实现的
# 之前没注意过,查找空字符串位置,一起看一下
public boolean contains(CharSequence s) {
    # s为空字符串 indexOf返回的结果为0
    return indexOf(s.toString()) > -1;
}


public int indexOf(String str) {
    # 在此处,默认查找字符串的开始下标位置(第二个参数)为0
    # str为空时,返回的位置为开始下标位置,逻辑详见indexOf实现方法;
    return indexOf(str, 0);
}

public int indexOf(String str, int fromIndex) {
    # 字符串位置查找的全部参数,分三部分:
    #     1、资源字符串:   值的char数组、开始位置、长度
    #     2、目标字符串: 值的char数组、开始位置、长度
    #     3、开始下标
    #
    # 此处均资源字符、目标字符串的开始位置、查找长度进行默认;
    #
    # 有一个特殊的写法,String类的value属性,学习了
    # 写作: private final char value[];

    return indexOf(value, 0, value.length,
            str.value, 0, str.value.length, fromIndex);
}

# indexOf的逻辑实现方法
static int indexOf(char[] source, int sourceOffset, int sourceCount,
        char[] target, int targetOffset, int targetCount,
        int fromIndex) {

    if (fromIndex >= sourceCount) {
        # 1、此处,当目标长度为0时,直接返回sourceCount
        return (targetCount == 0 ? sourceCount : -1);
    }
    if (fromIndex < 0) {
        fromIndex = 0;
    }

    # 2、此处,目标字长度为0时, 也可能返回fromIndex的值
    # 结合1、2, 也就是说目标长度为0,
    # 返回的数值实际上不是目标在资源中的具体位置!!!!!!
    if (targetCount == 0) {
        return fromIndex;
    }


    char first = target[targetOffset];

    # 这个地方为节省循环次数,对查找的最大范围做界定
    # 开始位置为sourceOffset的前提下
    # 能比对的字符串最大长度 就是: sourceCount - targetCount
    int max = sourceOffset + (sourceCount - targetCount);
    for (int i = sourceOffset + fromIndex; i <= max; i++) {
        
        # 查找第一个相同的char的位置
        if (source[i] != first) {
            while (++i <= max && source[i] != first);
        }

        if (i <= max) {
            int j = i + 1;
            int end = j + targetCount - 1;

            # 按照目标长度,逐个字符进行比对
            # 确定目标字符串全部都在资源字符串中
            for (int k = targetOffset + 1; j < end && source[j]
                    == target[k]; j++, k++);

            # 若长度一致  返回位置
            # 此处返回的位置 是基于sourceOffset的位置
            if (j == end) {
                return i - sourceOffset;
            }
        }
    }
    return -1;
}

总结:
    1、 contains返回true, 不一定代表包含关系, 也可能是查找的字符串为空;

    以下为String.indexOf方法的总结,未对外暴漏,可以看看*********************************
    2、 indexOf方法,开始下标>资源查找长度时,返回的不一定为-1(未找到), 也有肯能是 资源查找长度;
    3、 indexOf方法,开始下标<=资源查找长度, 且目标长度为0时,返回的是开始下标位置;
    4、 indexOf方法,返回的位置是基于sourceOffset的值,也就是说,返回值为0不一定代表目标字符串在字符串的开头;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值