¿Alguien puede decirme el beneficio de que Java 17 acepte expresiones finales como una expresión de caso en construcciones de caso de cambio, pero no acepta que la expresión final se pase como parámetro?
void test(int distinction, final int foo) { final var bar = 2; switch (distinction) { case foo -> doSomething(); // does not compile -> case expressions must be constant expressions case bar -> doSomething(); // does compile case 3 -> doOtherThings(); // does compile } }¿Por qué el compilador no acepta el caso 1, aunque foo es una variable final como lo es bar?
En mi opinión, la legibilidad del caso 3 es mucho mejor que la del caso 2. Por lo tanto, no veo el beneficio de la nueva construcción del lenguaje.
Las etiquetas de los casos deben ser constantes de tiempo de compilación . Un parámetro final no es una constante de tiempo de compilación; puede que no varíe a lo largo de una invocación determinada del método, pero puede variar a lo largo de las invocaciones del método. (Los campos de instancia final y los campos finales estáticos sin un inicializador tampoco son constantes de tiempo de compilación).
Su declaración "Así que no veo el beneficio de la nueva construcción del lenguaje" contiene la suposición incorrecta de que había una nueva construcción del lenguaje involucrada.
La definición de constantes de tiempo de compilación no ha cambiado desde Java 1.0.
Una variable constante es una variable
finalde tipo primitivo o de tipoStringque se inicializa con una expresión constante ( §15.29 ).
Entonces, contrariamente a los mitos tenaces populares, una constante de tiempo de compilación no tiene que ser static ni necesita ser un campo en absoluto. Una variable local final , inicializada con una expresión constante es una constante de tiempo de compilación. Por el contrario, un parámetro que nunca tiene un inicializador nunca puede ser una constante de tiempo de compilación.
Además, la regla de que las etiquetas de switch deben ser constantes en tiempo de compilación cuando son de un tipo entero nunca cambia. Esto es más difícil de reconocer, ya que se agregó soporte para otras etiquetas de casos, Java 5 introdujo la posibilidad de cambiar tipos de enum , Java 7 agregó soporte para cambiar valores de String y la nueva coincidencia de patrones permitirá cambiar tipos. En el caso de las etiquetas de tipo o enum , las etiquetas de caso no son constantes de tiempo de compilación, sino nombres simbólicos invariantes, por lo que no puede usar nombres de variables en absoluto al cambiar una enum o tipo.
Entonces, el siguiente programa funciona en todas las versiones de Java:
class SwitchTest { public static void main(String[] args) { final int one = 1, two = 2; switch(args.length) { case one: System.out.println("one"); break; case two: System.out.println("two"); break; case one + two: System.out.println("three"); break; } } }No hay necesidad de casos prácticos de uso aquí. Tener reglas simples y consistentes es mejor que tener reglas complicadas que intentan excluir combinaciones que parecen inútiles.
Como apéndice, desde Java 5, que introdujo anotaciones, el siguiente es un código legal
class Test { @interface Example { String value(); } public static void main(String[] args) { final String str = "test"; @Example(str) class Local {} } }lo que demuestra la consistencia de las reglas. Las anotaciones requieren que los valores sean constantes de tiempo de compilación, por lo que es posible usar una variable local en una anotación, si la variable es una constante de tiempo de compilación.