Las declaraciones de cambio con String
casos se han implementado en Java SE 7 , al menos 16 años después de que se solicitaron por primera vez. No se proporcionó una razón clara para la demora, pero probablemente tuvo que ver con el rendimiento.
Implementación en JDK 7
La característica ahora se ha implementado javac
con un proceso de "des-azúcar"; una sintaxis limpia y de alto nivel que usa String
constantes en las case
declaraciones se expande en tiempo de compilación en un código más complejo siguiendo un patrón. El código resultante utiliza instrucciones JVM que siempre han existido.
A switch
con String
casos se traduce en dos interruptores durante la compilación. El primero asigna cada cadena a un número entero único: su posición en el interruptor original. Esto se hace activando primero el código hash de la etiqueta. El caso correspondiente es una if
declaración que prueba la igualdad de cadena; Si hay colisiones en el hash, la prueba es en cascada if-else-if
. El segundo conmutador refleja eso en el código fuente original, pero sustituye las etiquetas de los casos con sus posiciones correspondientes. Este proceso de dos pasos facilita la preservación del control de flujo del interruptor original.
Interruptores en la JVM
Para obtener más detalles técnicos sobre switch
, puede consultar la Especificación JVM, donde se describe la compilación de las instrucciones del conmutador . En pocas palabras, hay dos instrucciones JVM diferentes que se pueden usar para un conmutador, dependiendo de la escasez de las constantes utilizadas por los casos. Ambos dependen del uso de constantes enteras para que cada caso se ejecute de manera eficiente.
Si las constantes son densas, se usan como un índice (después de restar el valor más bajo) en una tabla de punteros de instrucción: la tableswitch
instrucción.
Si las constantes son escasas, se realiza una búsqueda binaria del caso correcto: la lookupswitch
instrucción.
Al quitar el azúcar switch
a los String
objetos, es probable que se utilicen ambas instrucciones. El lookupswitch
es adecuado para el primer interruptor de códigos hash para encontrar la posición original de la caja. El ordinal resultante es un ajuste natural para a tableswitch
.
Ambas instrucciones requieren que las constantes enteras asignadas a cada caso se ordenen en tiempo de compilación. En tiempo de ejecución, aunque el O(1)
rendimiento de tableswitch
generalmente parece mejor que el O(log(n))
rendimiento de lookupswitch
, requiere un análisis para determinar si la tabla es lo suficientemente densa como para justificar la compensación espacio-tiempo. Bill Venners escribió un gran artículo que cubre esto con más detalle, junto con una mirada oculta a otras instrucciones de control de flujo de Java.
Antes de JDK 7
Antes de JDK 7, enum
podría aproximarse a un String
interruptor basado en. Esto utiliza elvalueOf
método estático generado por el compilador en cada enum
tipo. Por ejemplo:
Pill p = Pill.valueOf(str);
switch(p) {
case RED: pop(); break;
case BLUE: push(); break;
}