Index: src/org/openstreetmap/josm/data/validation/OsmValidator.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 18972)
+++ src/org/openstreetmap/josm/data/validation/OsmValidator.java	(working copy)
@@ -15,6 +15,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.EnumMap;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -683,6 +684,7 @@
 
     /**
      * Groups the given collection of errors by severity, then message, then description.
+     * Uses <code>AlphanumComparator</code> for grouping the strings.
      * @param errors list of errors to group
      * @param filterToUse optional filter
      * @return collection of errors grouped by severity, then message, then description
@@ -690,13 +692,30 @@
      */
     public static Map<Severity, Map<String, Map<String, List<TestError>>>> getErrorsBySeverityMessageDescription(
             Collection<TestError> errors, Predicate<? super TestError> filterToUse) {
-        return errors.stream().filter(filterToUse).collect(
+        return getErrorsBySeverityMessageDescription(errors, filterToUse, AlphanumComparator.getInstance());
+    }
+
+    /**
+     * Groups the given collection of errors by severity, then message, then description.
+     * Uses the given comparator for grouping the strings.
+     * @param errors list of errors to group
+     * @param filterToUse optional filter
+     * @param comparator the String comparator to use for grouping the messages and descriptions
+     * @return collection of errors grouped by severity, then message, then description
+     * @since xxx
+     */
+    public static Map<Severity, Map<String, Map<String, List<TestError>>>> getErrorsBySeverityMessageDescription(
+            Collection<TestError> errors, Predicate<? super TestError> filterToUse, final Comparator<String> comparator) {
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        Map<Severity, Map<String, Map<String, List<TestError>>>>  x = errors.stream().filter(filterToUse).collect(
                 Collectors.groupingBy(TestError::getSeverity, () -> new EnumMap<>(Severity.class),
-                        Collectors.groupingBy(TestError::getMessage, () -> new TreeMap<>(AlphanumComparator.getInstance()),
+                        Collectors.groupingBy(TestError::getMessage, () -> new TreeMap<>(comparator),
                                 Collectors.groupingBy(e -> e.getDescription() == null ? "" : e.getDescription(),
-                                        () -> new TreeMap<>(AlphanumComparator.getInstance()),
+                                        () -> new TreeMap<>(comparator),
                                         Collectors.toList()
                                 ))));
+        Logging.debug("getErrorsBySeverityMessageDescription took "  + stopwatch.toString());
+        return x;
     }
 
     /**
Index: src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanel.java	(revision 18972)
+++ src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanel.java	(working copy)
@@ -209,7 +209,7 @@
             filterToUse = filterToUse.and(e -> e.getPrimitives().stream().anyMatch(filter::contains));
         }
         Map<Severity, Map<String, Map<String, List<TestError>>>> errorsBySeverityMessageDescription
-            = OsmValidator.getErrorsBySeverityMessageDescription(errors, filterToUse);
+            = OsmValidator.getErrorsBySeverityMessageDescription(errors, filterToUse, String::compareTo);
 
         final List<TreePath> expandedPaths = new ArrayList<>();
         for (Entry<Severity, Map<String, Map<String, List<TestError>>>> entry: errorsBySeverityMessageDescription.entrySet()) {
