现状
一般情况下,我们使用字符串的前置匹配方法,如果要做的通用一些,忽略大小写,可能会这么写:
复制
从功能上说,这么写当然没问题。但是,我们忽略了一个问题:toLowerCase(toUpperCase) 方法是耗时的。为什么耗时?以 toLowerCase 为例:
复制
会遍历字符串并且重新赋值给 newString,最终调用的是 Character.toLowerCase 方法:
复制
最后这里的 toLowerCaseImpl 就是真正实现的方法,这是一个 Native 方法,也是由 C/C++ 完成的。
toLowerCaseImpl 效率高,然而在调用 toLowerCaseImpl 之前的操作,会耗时。那我们最开始的 startsWithIgnoreCase 方法的性能瓶颈就在这里了。如果想要减少耗时,应该怎么办呢?
分析
耗时关键点:toLowerCase。这个方法,当然是没什么替代的空间, 只能另辟蹊径。关于 String 的忽略大小写比对,除了 toLowerCase 和 toUpperCase 之后再比对,我们还会想到一个方法:equalsIgnoreCase。
这个方法的效率会比先 toLowerCase 之后再比对的效率高。为什么呢?
复制
并不会对字符串进行全拷贝,foldCase 就直接调用到上文中 Character.toLowerCase 方法,最后调用到 toLowerCaseImpl 方法。
实现
说了这么多,肯定有小伙伴会问:我们不是在聊字符串前置匹配吗?equals 速度快了和前置匹配有什么关系呢?
让我们想想前置匹配的逻辑:处理好忽略大小写后的字符串,进行 startsWith 操作,是不是可以等同于,字符串 str 截取从下标为 0 到 prefix.length 的位置,这部分前置字符串再和 prefix 进行 equalsIgnoreCase?如果 str 的长度小于等于 prefix 的长度,其实 startsWith 和 equals 是一样的。
逻辑已经梳理清楚了,那么就简单了,动手写一下新的忽略字符串大小写的前置匹配通用方法:
复制
方法写好了,让我们写个 Demo 验证一下是否真的有优化效果吧。
验证
上 Demo 代码:
复制
这里的 startsWithIgnoreCaseNew 方法就是新实现的 startsWithIgnoreCase 方法。当 str 和 prefix 完全一样的时候,验证结果如下:
如果在 str 和 prefix 中随机加一些大写字符,验证结果如下:
高下立判!
高下立判!
高下立判!
领取专属 10元无门槛券
私享最新 技术干货