java java-8 switch-statement

¿Por qué en un conmutador Java 8 sobre un contenedor Integer, no se compila un caso ''char'', pero la compilación está bien cuando el conmutador ha pasado por Byte?



java-8 switch-statement (1)

Los motivos son bastante complicados, pero todos están en los detalles ( letra pequeña si lo desea) de la Especificación del lenguaje Java.

Primero, el JLS 14.11 dice lo siguiente sobre las declaraciones de switch :

"Cada constante de caso asociada con la declaración de cambio debe ser compatible con el tipo de expresión de la declaración de cambio ( §5.2 )".

Esto significa que ''a'' debe ser asignable a Integer y Byte respectivamente.

Pero eso no suena bien:

  • Se podría pensar que ya que ''a'' debería ser asignable a un número Integer porque la asignación char -> int es legal. (Cualquier valor de char encajará en un int .)

  • Pensaría que dado que ''a'' NO debe ser asignable a un Byte porque la asignación de char -> byte NO es legal. (La mayoría de los valores de caracteres no caben en un byte).

De hecho, ninguno de estos es correcto. Para entender por qué, necesitamos leer lo que §5.2 realmente trata sobre lo que está permitido en contextos de asignación.

"Los contextos de asignación permiten el uso de uno de los siguientes :

  • una conversión de identidad (§5.1.1)
  • una conversión primitiva cada vez mayor (§5.1.2)
  • Una conversión de referencia cada vez mayor (§5.1.5)
  • una conversión de referencia cada vez mayor seguida de una conversión de unboxing
  • una conversión de referencia de ampliación seguida de una conversión de unboxing, seguida de una conversión primitiva de ampliación
  • una conversión de boxeo (§5.1.7)
  • una conversión de boxeo seguida de una conversión de referencia cada vez mayor
  • una conversión de unboxing (§5.1.8)
  • una conversión de unboxing seguida de una conversión primitiva cada vez mayor ".

Para ir de ''a'' a Integer , necesitaríamos 1 ampliar el valor de char a un int luego encajonar el int a un Integer . Pero si observa las combinaciones de conversiones permitidas, no puede hacer una conversión primitiva de ampliación seguida de una conversión de boxeo.

Por lo tanto, ''a'' a Integer no está permitido. Esto explica el error de compilación en el primer caso.

Se podría pensar que ''a'' a Byte no está permitido porque eso implicaría una conversión de estrechamiento primitiva ... que no está en la lista en absoluto. De hecho, los literales son un caso especial. §5.2 continúa diciendo lo siguiente.

"Además, si la expresión es una expresión constante ( §15.28 ) de tipo byte, short, char o int:

  • Se puede usar una conversión primitiva estrecha si la variable es de tipo byte, short o char, y el valor de la expresión constante es representable en el tipo de la variable.

  • Se puede usar una conversión primitiva de estrechamiento seguida de una conversión de boxeo si la variable es de tipo Byte , Short o Character , y el valor de la expresión constante es representable en el tipo byte, short o char respectivamente ".

El segundo de estos se aplica a ''a'' a Byte , porque:

  • un carácter literal es una expresión constante y
  • el valor de ''a'' es 97 decimal, que está dentro del rango del byte ( -128 a +127 ).

Esto explica por qué no hay error de compilación en el segundo ejemplo.

1 - No podemos encajonar ''a'' a un Character y luego ampliar Character a Integer porque el Character no es un subtipo Java de Integer . Solo puede usar una conversión de referencia de ampliación si el tipo de origen es un subtipo del tipo de destino.

No compila:

void test(Integer x){ switch(x){ case ''a'': } }

Compila bien:

void test(Byte x){ switch(x){ case ''a'': } }