Collation compares natural-language strings under a locale and strength policy; comparator equality can group labels that String.equals still treats as different.
Java collation: display order and distinct stored labels
Java 8+. The program uses JDK classes and requires no preview flags.
Sorting is not identifier equality
A customer directory can sort labels without treating every case or accent difference as a new primary position. That is a presentation decision. An account identifier still needs its own exact or normalized equality contract; using the directory comparator as a map-key rule can merge accounts that should remain distinct.
The program uses a French collator at primary strength. It compares two labels that differ by an accent and then shows the membership effect in TreeSet. The second set adds a UTF-16 tie-break so comparator-equivalent spellings remain separate values. The set is ordered by that combined rule, not just by the collator.
The locale is explicit. A default-locale comparison can change when the application moves to a machine with another language setting. Locale data can also change across JDK releases. Store stable identifiers independently of the user’s display order, and state the runtime when a test asserts a particular ordering.
Treat configuration as owned state
Collator configuration includes strength and decomposition mode. Configure an instance before using it in a sorted collection, then keep that rule fixed for the collection’s lifetime. Changing a comparator’s behavior after insertion can invalidate search assumptions even if no label object changed.
Working program
import java.text.Collator;
import java.util.*;
public class CustomerDirectoryOrder {
public static void main(String[] args){
Collator french=Collator.getInstance(Locale.FRENCH);french.setStrength(Collator.PRIMARY);
String first="cote",second="c\u00f4te";
TreeSet<String> grouped=new TreeSet<>((a,b)->french.compare(a,b));
grouped.add(first);grouped.add(second);
Comparator<String> distinct=(a,b)->{int compared=french.compare(a,b);return compared!=0?compared:a.compareTo(b);};
TreeSet<String> labels=new TreeSet<>(distinct);labels.add(first);labels.add(second);
System.out.println(french.compare(first,second)==0);
System.out.println(grouped.size());System.out.println(labels.size());
}
}Output
true
1
2Costs and boundaries
A comparison examines the strings under the chosen locale rules. Sorting performs O(n log n) comparisons for n labels, with text-processing costs inside each comparison. A tie-break preserves distinct spellings but does not create a universal cross-version collation order.
Common Mistakes
- Comparator equality can collapse TreeSet membership.
- The machine’s default locale is not an explicit application policy.
- Do not change comparator settings after insertion.
