uso switch ejemplo java string switch-statement

ejemplo - switch string java 6



¿Por qué no puedo usar la instrucción switch en un String? (14)

¿Se va a poner esta funcionalidad en una versión posterior de Java?

¿Alguien puede explicar por qué no puedo hacer esto, como en la forma técnica en que funciona la instrucción de switch de Java?


Además de los buenos argumentos anteriores, agregaré que muchas personas hoy en día consideran el switch como un resto obsoleto del pasado procesal de Java (de vuelta a C).

No comparto completamente esta opinión, creo que switch puede tener su utilidad en algunos casos, al menos debido a su velocidad, y de todos modos es mejor que alguna otra serie de números numéricos en cascada else if veo en algún código ...

Pero, de hecho, vale la pena examinar el caso en el que necesita un interruptor y ver si no puede ser reemplazado por algo más OO. Por ejemplo, enumeraciones en Java 1.5+, quizás HashTable o alguna otra colección (en algún momento lamento que no tengamos funciones (anónimas) como ciudadano de primera clase, como en Lua, que no tiene conmutador, o JavaScript) o incluso polimorfismo.


Cuando usas intellij también miras:

Archivo -> Estructura del proyecto -> Proyecto

Archivo -> Estructura del proyecto -> Módulos

Cuando tenga varios módulos, asegúrese de configurar el nivel de idioma correcto en la pestaña del módulo.


Durante años hemos estado usando un preprocesador (n de código abierto) para esto.

//#switch(target) case "foo": code; //#end

Los archivos preprocesados ​​se llaman Foo.jpp y se procesan en Foo.java con un script ant.

La ventaja es que se procesa en Java que se ejecuta en 1.0 (aunque, por lo general, solo admitimos la versión 1.4). También fue mucho más fácil hacer esto (muchos interruptores de cadena) en comparación con usar enumeración u otras soluciones alternativas; el código era mucho más fácil de leer, mantener y entender. IIRC (no puede proporcionar estadísticas o razonamiento técnico en este punto) también fue más rápido que los equivalentes naturales de Java.

Las desventajas son que no está editando Java, por lo que es un poco más de flujo de trabajo (editar, procesar, compilar / probar) además de que un IDE se vinculará a Java, que está un poco complicado (el interruptor se convierte en una serie de pasos lógicos si / de lo contrario) y el orden de la caja del interruptor no se mantiene.

No lo recomendaría para la versión 1.7+, pero es útil si desea programar Java orientado a JVM anteriores (ya que Joe public rara vez tiene la última versión instalada).

Puede obtenerlo de SVN o navegar el código en línea . Necesitarás EBuild para construirlo como está.


El siguiente es un ejemplo completo basado en la publicación de JeeBee, utilizando enumas java en lugar de usar un método personalizado.

Tenga en cuenta que en Java SE 7 y versiones posteriores, puede usar un objeto String en la expresión de la instrucción switch en su lugar.

public class Main { /** * @param args the command line arguments */ public static void main(String[] args) { String current = args[0]; Days currentDay = Days.valueOf(current.toUpperCase()); switch (currentDay) { case MONDAY: case TUESDAY: case WEDNESDAY: System.out.println("boring"); break; case THURSDAY: System.out.println("getting better"); case FRIDAY: case SATURDAY: case SUNDAY: System.out.println("much better"); break; } } public enum Days { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } }


Es una brisa en Groovy; Incrusté el jar de groovy y creo una clase de utilidad groovy para hacer todas estas cosas y más que me resulta exasperante hacer en Java (ya que estoy atascado con Java 6 en la empresa).

it.''p''.each{ switch ([email protected]()){ case "choclate": myholder.myval=(it.text()); break; }}...


James Curran dice sucintamente: "Los conmutadores basados ​​en enteros se pueden optimizar para obtener un código muy eficiente. Los conmutadores basados ​​en otro tipo de datos solo se pueden compilar en una serie de sentencias if (). Por esa razón, C & C ++ solo permite conmutadores en tipos enteros, Ya que era inútil con otros tipos ".

Mi opinión, y es solo eso, es que tan pronto como comienza a activar los no primitivos, debe comenzar a pensar en "iguales" frente a "==". En primer lugar, comparar dos cadenas puede ser un procedimiento bastante largo, que se agrega a los problemas de rendimiento que se mencionan anteriormente. En segundo lugar, si hay conmutación de cadenas, habrá demanda para activar cadenas ignorando el caso, activando cadenas considerando / ignorando la configuración regional, activando cadenas basadas en expresiones regulares ... aprobaría una decisión que ahorró mucho tiempo para el Desarrolladores de lenguaje a costa de una pequeña cantidad de tiempo para los programadores.


Las declaraciones de cambio con casos de String se han implementado en Java SE 7 , al menos 16 años bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179 No se proporcionó una razón clara para el retraso, pero probablemente tuvo que ver con el rendimiento.

Implementación en JDK 7

La característica ahora se ha implementado en javac con un proceso de "des-azucarado"; una sintaxis limpia de alto nivel que usa constantes de String en case declaraciones se expandan 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.

Un switch con casos de String se traduce en dos conmutadores durante la compilación. La primera asigna cada cadena a un entero único: su posición en el interruptor original. Esto se hace primero activando el código hash de la etiqueta. El caso correspondiente es una sentencia if que prueba la igualdad de cadenas; Si hay colisiones en el hash, la prueba es en cascada if-else-if . El segundo interruptor refleja eso en el código fuente original, pero sustituye las etiquetas de las cajas con sus posiciones correspondientes. Este proceso de dos pasos facilita la conservación del control de flujo del interruptor original.

Interruptores en la JVM

Para obtener más información técnica sobre el switch , puede consultar la Especificación JVM, donde se describe la compilación de las declaraciones del switch . En pocas palabras, hay dos instrucciones JVM diferentes que se pueden usar para un cambio, 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 indicadores de instrucción: la instrucción de tableswitch .

Si las constantes son dispersas, se realiza una búsqueda binaria del caso correcto: la instrucción del lookupswitch .

Al quitar el azúcar de un switch en los objetos String , es probable que se utilicen ambas instrucciones. El lookupswitch es adecuado para el primer interruptor en códigos hash para encontrar la posición original de la caja. El ordinal resultante es un ajuste natural para un tableswitch .

Ambas instrucciones requieren que las constantes enteras asignadas a cada caso se clasifiquen en el momento de la compilación. En el tiempo de ejecución, mientras que el rendimiento de O(1) del tableswitch de tableswitch generalmente parece mejor que el rendimiento de O(log(n)) del lookupswitch , requiere un análisis para determinar si la tabla es lo suficientemente densa como para justificar la compensación de espacio-tiempo. Bill Venners escribió un excelente artículo que cubre esto con más detalle, junto con un vistazo a otras instrucciones de control de flujo de Java.

Antes de JDK 7

Antes de JDK 7, la enum podría aproximarse a un conmutador basado en String . Esto utiliza el método static valueOf generado por el compilador en cada tipo de enum . Por ejemplo:

Pill p = Pill.valueOf(str); switch(p) { case RED: pop(); break; case BLUE: push(); break; }


Los conmutadores basados ​​en enteros se pueden optimizar para obtener un código muy eficiente. Los conmutadores basados ​​en otro tipo de datos solo se pueden compilar en una serie de sentencias if ().

Por esa razón, C y C ++ solo permiten conmutadores en tipos enteros, ya que no tenía sentido con otros tipos.

Los diseñadores de C # decidieron que el estilo era importante, incluso si no había ninguna ventaja.

Los diseñadores de Java aparentemente pensaron como los diseñadores de C.


No es muy bonito, pero aquí hay otra forma para Java 6 y más abajo:

String runFct = queryType.equals("eq") ? "method1": queryType.equals("L_L")? "method2": queryType.equals("L_R")? "method3": queryType.equals("L_LR")? "method4": "method5"; Method m = this.getClass().getMethod(runFct); m.invoke(this);


Otras respuestas han dicho que esto se agregó en Java 7 y se proporcionaron soluciones alternativas para versiones anteriores. Esta respuesta trata de responder al "por qué".

Java fue una reacción a las complejidades excesivas de C ++. Fue diseñado para ser un lenguaje simple y limpio.

String consiguió un poco de manejo de casos especiales en el lenguaje, pero me parece claro que los diseñadores intentaban mantener la cantidad de tripa especial y azúcar sintáctica al mínimo.

cambiar cadenas es bastante complejo bajo el capó, ya que las cadenas no son simples tipos primitivos. No era una característica común en el momento en que se diseñó Java y realmente no encaja bien con el diseño minimalista. Especialmente porque decidieron no usar el caso especial == para cadenas, sería (y es) un poco extraño que el caso funcione donde == no.

Entre 1.0 y 1.4 el lenguaje en sí se mantuvo prácticamente igual. La mayoría de las mejoras a Java estaban en el lado de la biblioteca.

Todo eso cambió con Java 5, el lenguaje se amplió sustancialmente. Otras extensiones seguidas en las versiones 7 y 8. Espero que este cambio de actitud haya sido impulsado por el aumento de C #


Si no está utilizando JDK7 o superior, puede usar hashCode() para simularlo. Debido a que String.hashCode() generalmente devuelve valores diferentes para cadenas diferentes y siempre devuelve valores iguales para cadenas iguales, es bastante confiable (cadenas diferentes pueden producir el mismo código hash que @Lii mencionado en un comentario, como "FB" y "Ea" ) Ver documentation .

Entonces, el código se vería así:

String s = "<Your String>"; switch(s.hashCode()) { case "Hello".hashCode(): break; case "Goodbye".hashCode(): break; }

De esa manera, usted está técnicamente activando un int .

Alternativamente, podrías usar el siguiente código:

public final class Switch<T> { private final HashMap<T, Runnable> cases = new HashMap<T, Runnable>(0); public void addCase(T object, Runnable action) { this.cases.put(object, action); } public void SWITCH(T object) { for (T t : this.cases.keySet()) { if (object.equals(t)) { // This means that the class works with any object! this.cases.get(t).run(); break; } } } }


Si tiene un lugar en su código donde puede activar una Cadena, entonces puede ser mejor refactorizar la Cadena para que sea una enumeración de los valores posibles, que puede activar. Por supuesto, limita los valores potenciales de las cadenas que puede tener a aquellos en la enumeración, que pueden o no desearse.

Por supuesto, su enumeración podría tener una entrada para ''otro'' y un método fromString (String), entonces podría tener

ValueEnum enumval = ValueEnum.fromString(myString); switch (enumval) { case MILK: lap(); break; case WATER: sip(); break; case BEER: quaff(); break; case OTHER: default: dance(); break; }


También se puede mostrar un ejemplo de uso directo de String desde 1.7:

public static void main(String[] args) { switch (args[0]) { case "Monday": case "Tuesday": case "Wednesday": System.out.println("boring"); break; case "Thursday": System.out.println("getting better"); case "Friday": case "Saturday": case "Sunday": System.out.println("much better"); break; } }


public class StringSwitchCase { public static void main(String args[]) { visitIsland("Santorini"); visitIsland("Crete"); visitIsland("Paros"); } public static void visitIsland(String island) { switch(island) { case "Corfu": System.out.println("User wants to visit Corfu"); break; case "Crete": System.out.println("User wants to visit Crete"); break; case "Santorini": System.out.println("User wants to visit Santorini"); break; case "Mykonos": System.out.println("User wants to visit Mykonos"); break; default: System.out.println("Unknown Island"); break; } } }