请看下面的代码:
"i".equals(xx.toLowerCase());
其中,xx 是服务端返回的字段,字段值是“I”(大写的i)。
看到这样的代码,我们可能不假思索的认为肯定是 true 啊,不可能有其他值。
真的是这样吗?天哥还真遇到了为 false 的情况。
经测试和验证发现,Android/Java 在默认 Locale 被设置成土耳其语的情况下,使用 toLowerCase会导致“I”变成“ı”,在源码注释中也有说明。
/**
* Converts all of the characters in this {@code String} to lower
* case using the rules of the default locale. This is equivalent to calling
* {@code toLowerCase(Locale.getDefault())}.
* <p>
* <b>Note:</b> This method is locale sensitive, and may produce unexpected
* results if used for strings that are intended to be interpreted locale
* independently.
* Examples are programming language identifiers, protocol keys, and HTML
* tags.
* For instance, {@code "TITLE".toLowerCase()} in a Turkish locale
* returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
* LATIN SMALL LETTER DOTLESS I character.
* To obtain correct results for locale insensitive strings, use
* {@code toLowerCase(Locale.ROOT)}.
* <p>
* @return the {@code String}, converted to lowercase.
* @see java.lang.String#toLowerCase(Locale)
*/
public String toLowerCase() {
return toLowerCase(Locale.getDefault());
}
所以我们文章开始的那段代码通常情况下都是正确的,因为我们几乎不会搞个土耳其语,也就忽视了这个问题。碰巧,天哥做国际化的,遇到了。
I 只是目前遇到的,是否还有其他字母在其他语言中有特殊转换,我们也不清楚楚。所以,为了保证 toLowerCase 的正确性,我们有两个解决方案:
1、使用 toLowerCase(Locale) 带 locale 参数的方法, Locale 设定为(en_US)。
"i".equals(xx.toLowerCase(Locale.US));
也就是把语义设置在英文环境下,就可以避免这个问题。
2、使用系统 equalsIgnoreCase 方法来做比较,也不会引入这个问题。
"i". equalsIgnoreCase(xx);