9

JEP 455 introduced Primitive Types in Patterns, instanceof, and switch as a preview feature in JDK 23. It continues as a preview feature in JDK 24 and 25, so the feature is not detailed in the Java Language Specification.

The JEP describes "safety of conversions", where certain pairs of types are unconditionally exact, meaning no runtime checks are required. For other pairs, a runtime test is necessary to determine if a conversion can be made without loss of information.

For example:

int x = getValue();  // Which returns 42

switch (x) {
  case byte -> System.out.println("byte");
  case int -> System.out.println("int");
}

The runtime check verifies that 42 will fit in a byte and matches, printing 'byte'.

If we change the order of the cases:

switch (x) {
  case int -> System.out.println("int");
  case byte -> System.out.println("byte");
}

This will result in a compiler error because the int case now dominates the byte case.

Quoting from the Java Language Specification (where pattern dominance is defined),

A switch label in a switch block is said to be dominated if for every value that it applies to, it can be determined that one of the preceding switch labels would also apply.

So far, everything makes sense.

However, if we change the case for int to use the wrapper class Integer:

switch (x) {
  case Integer -> System.out.println("int");
  case byte -> System.out.println("byte");
}

This code will compile without an error, and the result will be 'int'.

The compiler is clearly autoboxing the int to an Integer and matching the first case.

What I can't understand is why the compiler allows this, since the Integer case is still dominating the byte case. Any value that will match for a byte will also match for a boxed Integer.

JEP 507, the latest version states:

Furthermore, boxing conversions and widening reference conversions are unconditionally exact.

However, that still does not explain why the compiler is not rejecting this because of pattern dominance.

Just to be clear, all the examples use the same line, int x = getValue();, where getValue() returns 42.

3
  • 5
    "Any value that will match for a byte will also match for a boxed Integer." Is that actually the case? What about a boxed Byte? Commented Sep 10 at 17:10
  • 1
    I am a little surprised the compiler even bothers trying to check for dominance in this way. It's trying to help, but I wouldn't expect it to be perfect in the best of circumstances. Commented Sep 10 at 18:33
  • 1
    Just to be clear, all the examples use the same line, int x = getValue(), where getValue() returns 42. Commented Sep 10 at 19:07

1 Answer 1

8

Domination is a relationship between the patterns themselves. The selector expression does not matter.

(Whether or not the type of the selector expression should be considered for determining dominance is another matter, and outside of the scope of this answer.)

As Jon Skeet said in the comments,

"Any value that will match for a byte will also match for a boxed Integer." Is that actually the case? What about a boxed Byte?

From the preview spec, the Integer pattern does not dominate the byte pattern. The relevant quotes are

(14.11.1)

A case label with a case pattern q is dominated if there is a preceding unguarded case label in the switch block with a case pattern p, and p dominates q

(14.30.3)

A pattern p dominates a type pattern that declares a pattern variable of type T if p is unconditional for T.

A type pattern that declares a pattern variable of a type S is unconditional for a type T if there is a testing conversion that is unconditionally exact (5.7.2) from |T| to |S|.

None of these definitions refer to the selector expression of the switch.

For this case, we can substitute Integer for "S" and byte for "T" into the last quote, and show that there is no testing conversion that is unconditionally exact from byte to Integer.

The unconditionally exact testing conversions are (5.7.2):

  • an identity conversion
  • an exact widening primitive conversion
  • a widening reference conversion
  • a boxing conversion
  • a boxing conversion followed by a widening reference conversion

To convert from byte to Integer, we need an (exact) widening primitive conversion followed by a boxing conversion, which is not in the above list.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.