liveBook · Manning

String.toLowerCase

As explained in 100 Java Mistakes and How to Avoid Them

String.toLowerCase is a Java String method that returns a string with its characters converted to lowercase according to an optionally specified locale.

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

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains default-locale behavior, Turkish failures, comparison mismatches, length changes, and hash-code incompatibilities.
Examples
Uses Turkish I, mismatched prefix normalization, defensive prefix sets, and Greek sigma equality examples.
What it assumes
Assumes Java String comparison knowledge while establishing default JVM locale behavior and explicit locale selection.
What you can do after
Diagnose locale-sensitive conversions and choose explicit locales, assertions, or regionMatches for safer comparisons.
How it connects
Connects String.toUpperCase, Locale, equalsIgnoreCase, equals, hashCode, regionMatches, and static analysis.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.