Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 15981)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 15982)
@@ -283,12 +283,12 @@
         protected final GroupedMapCSSRule rule;
         /** Commands to apply in order to fix a matching primitive */
-        protected final List<FixCommand> fixCommands = new ArrayList<>();
+        protected final List<FixCommand> fixCommands;
         /** Tags (or arbitrary strings) of alternatives to be presented to the user */
-        protected final List<String> alternatives = new ArrayList<>();
+        protected final List<String> alternatives;
         /** An {@link org.openstreetmap.josm.gui.mappaint.mapcss.Instruction.AssignmentInstruction}-{@link Severity} pair.
          * Is evaluated on the matching primitive to give the error message. Map is checked to contain exactly one element. */
-        protected final Map<Instruction.AssignmentInstruction, Severity> errors = new HashMap<>();
+        protected final Map<Instruction.AssignmentInstruction, Severity> errors;
         /** MapCSS Classes to set on matching primitives */
-        protected final Set<String> setClassExpressions = new HashSet<>();
+        protected final Collection<String> setClassExpressions;
         /** Denotes whether the object should be deleted for fixing it */
         protected boolean deletion;
@@ -298,4 +298,22 @@
         TagCheck(GroupedMapCSSRule rule) {
             this.rule = rule;
+            this.fixCommands = new ArrayList<>();
+            this.alternatives = new ArrayList<>();
+            this.errors = new HashMap<>();
+            this.setClassExpressions = new HashSet<>();
+        }
+
+        TagCheck(TagCheck check) {
+            this.rule = check.rule;
+            this.fixCommands = Utils.toUnmodifiableList(check.fixCommands);
+            this.alternatives = Utils.toUnmodifiableList(check.alternatives);
+            this.errors = Utils.toUnmodifiableMap(check.errors);
+            this.setClassExpressions = Utils.toUnmodifiableList(check.setClassExpressions);
+            this.deletion = check.deletion;
+            this.group = check.group;
+        }
+
+        TagCheck toImmutable() {
+            return new TagCheck(this);
         }
 
@@ -372,5 +390,5 @@
                 MapCSSTagCheckerAsserts.checkAsserts(check, assertions, assertionConsumer);
             }
-            return check;
+            return check.toImmutable();
         }
 
Index: /trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 15981)
+++ /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 15982)
@@ -48,4 +48,5 @@
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
@@ -69,4 +70,5 @@
 import javax.script.ScriptEngineManager;
 
+import com.kitfox.svg.xml.XMLParseUtil;
 import org.openstreetmap.josm.spi.preferences.Config;
 
@@ -766,4 +768,19 @@
             return (List<T>) Arrays.asList(collection.toArray());
         }
+    }
+
+    /**
+     * Returns an unmodifiable map for the given map.
+     * Makes use of {@link Collections#emptyMap()} and {@link Collections#singletonMap} and {@link Map#ofEntries(Map.Entry[])} to save memory.
+     *
+     * @param map the map for which an unmodifiable map is to be returned
+     * @param <K> the type of keys maintained by this map
+     * @param <V> the type of mapped values
+     * @return an unmodifiable map
+     * @see <a href="https://dzone.com/articles/preventing-your-java-collections-from-wasting-memo">
+     *     How to Prevent Your Java Collections From Wasting Memory</a>
+     */
+    public static <K, V> Map<K, V> toUnmodifiableMap(Map<K, V> map) {
+        return XMLParseUtil.toUnmodifiableMap(map);
     }
 
Index: /trunk/test/unit/org/openstreetmap/josm/tools/UtilsTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/tools/UtilsTest.java	(revision 15981)
+++ /trunk/test/unit/org/openstreetmap/josm/tools/UtilsTest.java	(revision 15982)
@@ -14,7 +14,10 @@
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
 import java.util.regex.Pattern;
 
@@ -574,3 +577,22 @@
         assertEquals(Arrays.asList("foo", "bar", "baz"), Utils.toUnmodifiableList(new LinkedList<>(Arrays.asList("foo", "bar", "baz"))));
     }
+
+    /**
+     * Test of {@link Utils#toUnmodifiableMap}
+     */
+    @Test
+    public void testToUnmodifiableMap() {
+        assertSame(Collections.emptyMap(), Utils.toUnmodifiableMap(null));
+        assertSame(Collections.emptyMap(), Utils.toUnmodifiableMap(Collections.emptyMap()));
+        assertSame(Collections.emptyMap(), Utils.toUnmodifiableMap(new HashMap<>()));
+        assertSame(Collections.emptyMap(), Utils.toUnmodifiableMap(new TreeMap<>()));
+        assertEquals(Collections.singletonMap("foo", "bar"), Utils.toUnmodifiableMap(new HashMap<>(Collections.singletonMap("foo", "bar"))));
+        assertEquals(Collections.singletonMap("foo", "bar"), Utils.toUnmodifiableMap(new TreeMap<>(Collections.singletonMap("foo", "bar"))));
+        final Map<String, String> map4 = new HashMap<>();
+        map4.put("jjj", "foo");
+        map4.put("ooo", "bar");
+        map4.put("sss", "baz");
+        map4.put("mmm", ":-)");
+        assertEquals(map4, Utils.toUnmodifiableMap(map4));
+    }
 }
