String.toLowerCase() returns lowercase text, but its no-argument form uses the JVM's default locale. That makes it unsafe for normalizing protocol names, XML tags, YAML keys, or internal identifiers when users may run the program under different locales. section 6.2
Locale-sensitive normalization
Under the Turkish locale, the English letter I lowercases to dotless ı rather than i. Normalize machine-oriented text with an explicit locale, commonly Locale.ROOT, instead of relying on toLowerCase(). section 6.2 section 6.8
Avoid predictable failure modes by following these rules:
- Specify a locale when converting text whose meaning is not tied to the user's language. section 6.2
- Normalize both operands before comparing; lowercasing only the searched string can make a condition permanently false. section 6.8
- Prefer regionMatches(true, ...) for case-insensitive prefix or suffix matching when full-string normalization is unnecessary. section 6.8
- Do not assume case conversion preserves length or provides a hash compatible with equalsIgnoreCase(). section 6.2 section 7.8
boolean hasOneOfPrefixes(String str, Set<String> prefixes) {
String lowercased = str.toLowerCase(Locale.ROOT);
for (String prefix : prefixes) {
assert prefix.equals(prefix.toLowerCase(Locale.ROOT));
if (lowercased.startsWith(prefix)) {
return true;
}
}
return false;
}
Shows a defensive prefix-set check that uses Locale.ROOT and asserts lowercase prefixes. section 6.8
System.out.println("σ".toLowerCase(Locale.ROOT)); #1
System.out.println("ς".toLowerCase(Locale.ROOT)); #2
System.out.println("σ".toUpperCase(Locale.ROOT)); #3
System.out.println("ς".toUpperCase(Locale.ROOT)); #4
System.out.println("σ".equalsIgnoreCase("ς")); #5
Demonstrates Greek sigma cases whose lowercase results differ while equalsIgnoreCase() still treats them as equal. section 7.8
