ICU-21397 Allow null to unset options in Java NumberRangeFormatter
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterSettings.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterSettings.java
index 13734e1..6843f5e 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterSettings.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterSettings.java
@@ -149,41 +149,37 @@
         // of a MacroProps object at each step.
         // TODO: Remove the reference to the parent after the macros are resolved?
         RangeMacroProps macros = new RangeMacroProps();
+        // Bitmap: 1 if seen; 0 if unseen
+        long seen = 0;
         NumberRangeFormatterSettings<?> current = this;
         while (current != null) {
+            long keyBitmask = (1L << current.key);
+            if (0 != (seen & keyBitmask)) {
+                current = current.parent;
+                continue;
+            }
+            seen |= keyBitmask;
             switch (current.key) {
             case KEY_MACROS:
                 // ignored for now
                 break;
             case KEY_LOCALE:
-                if (macros.loc == null) {
-                    macros.loc = (ULocale) current.value;
-                }
+                macros.loc = (ULocale) current.value;
                 break;
             case KEY_FORMATTER_1:
-                if (macros.formatter1 == null) {
-                    macros.formatter1 = (UnlocalizedNumberFormatter) current.value;
-                }
+                macros.formatter1 = (UnlocalizedNumberFormatter) current.value;
                 break;
             case KEY_FORMATTER_2:
-                if (macros.formatter2 == null) {
-                    macros.formatter2 = (UnlocalizedNumberFormatter) current.value;
-                }
+                macros.formatter2 = (UnlocalizedNumberFormatter) current.value;
                 break;
             case KEY_SAME_FORMATTERS:
-                if (macros.sameFormatters == -1) {
-                    macros.sameFormatters = (boolean) current.value ? 1 : 0;
-                }
+                macros.sameFormatters = (boolean) current.value ? 1 : 0;
                 break;
             case KEY_COLLAPSE:
-                if (macros.collapse == null) {
-                    macros.collapse = (RangeCollapse) current.value;
-                }
+                macros.collapse = (RangeCollapse) current.value;
                 break;
             case KEY_IDENTITY_FALLBACK:
-                if (macros.identityFallback == null) {
-                    macros.identityFallback = (RangeIdentityFallback) current.value;
-                }
+                macros.identityFallback = (RangeIdentityFallback) current.value;
                 break;
             default:
                 throw new AssertionError("Unknown key: " + current.key);
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberRangeFormatterTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberRangeFormatterTest.java
index 0788513..02ffbfc 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberRangeFormatterTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberRangeFormatterTest.java
@@ -665,6 +665,26 @@
     }
 
     @Test
+    public void test21397_UnsetNull() {
+        assertFormatRange(
+            "Unset identity fallback",
+            NumberRangeFormatter.with()
+                .identityFallback(RangeIdentityFallback.RANGE)
+                .identityFallback(null),
+            new ULocale("en-us"),
+            "1–5",
+            "~5",
+            "~5",
+            "0–3",
+            "~0",
+            "3–3,000",
+            "3,000–5,000",
+            "4,999–5,001",
+            "~5,000",
+            "5,000–5,000,000");
+    }
+
+    @Test
     public void testPlurals() {
         // Locale sl has interesting plural forms:
         // GBP{