• Pattern Label Dominance

    — Paris Monuments Edition

    In Java's enhanced switch with pattern matching, multiple case labels might match the selector expression. To ensure clarity and predictability, the switch block checks the labels in the order they appear.

    The compiler will raise a compile-time error if it detects that a case label can never be reached because a previous one always matches first. This concept is called pattern label dominance.

    Let’s explore this with a French twist! 🗼🖼️⛪

    🚨 Example 1: Eiffel Tower dominates the rest

    static void describeMonument(Object monument) {
        switch (monument) {
            case Monument m -> // General case: catches anything that's a Monument
                System.out.println("A Parisian monument: " + m.getName());
            case EiffelTower e -> // ❌ Error: unreachable, 
                                  //because EiffelTower is a subtype of Monument
                System.out.println("The iconic Eiffel Tower!");
            default -> {
                break;
            }
        }
    }

    🧠 Explanation: The case Monument m matches all subclasses, including EiffelTower. So when the switch sees an EiffelTower, it already matches Monument, and will never reach the more specific case. That’s why the compiler says "label is dominated".

    🚫 Example 2: Pattern labels also dominate constants

    static void describeVisitors(Integer count) {
        switch (count) {
            case Integer i -> // Matches any Integer
                System.out.println("Visitor count: " + i);
            case 1889, 2024 -> // ❌ Error: dominated by the Integer pattern
                System.out.println("Important years for the Eiffel Tower!");
            default -> {
                break;
            }
        }
    }

    💡 Here, the pattern case Integer i already matches any number, so the specific constant cases 1889 and 2024 are never reached. The compiler complains again.

    🎨 Example 3: Enum pattern dominance with the Louvre

    enum MonumentColor { WHITE, GRAY, GOLD }
    
    static void paintMonument(MonumentColor color) {
        switch (color) {
            case MonumentColor c -> // General pattern for any enum value
                System.out.println("Color selected: " + c);
            case WHITE -> // ❌ Error: unreachable because WHITE is already matched above
                System.out.println("Painting it white like Sacré-Cœur!");
        }
    }

    Again, case MonumentColor c already catches everything in the enum, including WHITE. So the constant label is dominated.

    ✅ Guarded patterns do NOT dominate constants

    Here’s the twist: guarded patterns (those with when) don’t dominate constant values.

    static void categorizeHeight(Integer heightInMeters) {
        switch (heightInMeters) {
            case Integer h when h > 100 -> // Guarded pattern: only matches if height > 100
                System.out.println("A tall monument!");
            case 300 -> // ✔️ OK: specific case for Eiffel Tower’s height
                System.out.println("Exactly the height of the Eiffel Tower!");
            case Integer h -> // Fallback for all other integers
                System.out.println("A modest monument");
        }
    }

    🧠 Here, even though 300 is greater than 100, the compiler does not consider the guarded case (h > 100) as dominant. Guarded patterns are excluded from dominance checks for complexity reasons.

    ✅ Recommended Order for Case Labels

    To avoid confusion and compiler errors, follow this ordering convention:

    1. Constants first (e.g. case 300)
    2. Guarded patterns next (e.g. case Integer h when h > 100)
    3. Generic patterns last (e.g. case Integer h)
    static void betterCategorizeHeight(Integer height) {
        switch (height) {
            case 300 -> System.out.println("Exactly the Eiffel Tower!");
            case 45 -> System.out.println("About the height of the Arc de Triomphe.");
            case Integer h when h > 100 -> System.out.println("A tall monument.");
            case Integer h -> System.out.println("A short or medium monument.");
        }
    }

    🧾 Summary