¿Cuál es el beneficio de activar Strings en Java 7?


19

Cuando comenzaba a programar en Java, el hecho de que las declaraciones de cambio no tomaran cadenas me frustraba. Luego, al usar Enums, me di cuenta de los beneficios que obtienes con ellos en lugar de pasar valores en bruto: seguridad de tipo (que brinda una refactorización más fácil) y también claridad para otros desarrolladores.

Me cuesta pensar en una situación en la que con SE7 ahora decidiré usar un interruptor con cadenas como entradas en lugar de Enums. Si se implementan activando cadenas enteras (por ejemplo, en lugar de coincidencias parciales o expresiones regulares), no parece ofrecer menos razones para que el código cambie.

Y con las herramientas IDE y la relación de lectura y escritura de la codificación, sería mucho más feliz generar automáticamente una enumeración adicional que pasar valores de cadena.

¿Qué beneficio nos aportan como programadores? ¿Menos placa de caldera?

No parece que el idioma estuviera pidiendo esta característica. Aunque tal vez hay un caso de uso que estoy pasando por alto.


Las cadenas ya se usan mucho en las declaraciones de cambio, pero debido a que las personas no podían usarlas directamente, recurrieron a soluciones alternativas como árboles gigantes o, si no, árboles o conversiones a enumeraciones. Ambas soluciones hacen que el código sea menos legible. Ambas formas son soluciones alternativas y por qué usar una solución alternativa si una solución implementada de forma nativa muestra mejor las intenciones de los programadores.
Pieter B

@PieterB Sin embargo, podría decirse que un Enum agrega valor semántico en lugar de ser una solución alternativa, lo que brinda seguridad de tipo (por ejemplo, un error tipográfico se detectará en el momento de la compilación en lugar de provocar un error). También nos permite refactorizar todas las instancias de la cadena, como se usa en ese contexto , sin afectar otros usos de esa cadena (lo que puede ocurrir con bastante frecuencia con los objetos de dominio)
Otra vez el

Respuestas:


12

Por lo que puedo decir, la pregunta es por qué envolver las constantes de String en enum no se ha considerado suficiente para cubrir las necesidades de los usuarios del lenguaje. Esto se ha abordado en la propuesta de función oficial anunciada en la lista de correo JDK 7 (proyecto de moneda).

Según mi lectura de la propuesta, se ha descartado la alternativa de usar enumeraciones debido a que introduce tipos de hinchazón. Para su conveniencia, la parte relevante de la propuesta se cita a continuación, con la declaración que aborda las enumeraciones en negrita :

VENTAJA PRINCIPAL: ¿Qué hace que la propuesta sea un cambio favorable?

Se pueden usar patrones de codificación más regulares para operaciones seleccionadas en base a un conjunto de valores de cadena constantes; El significado de la nueva construcción debería ser obvio para los desarrolladores de Java.

BENEFICIOS PRINCIPALES: ¿Por qué la plataforma es mejor si se adopta la propuesta?

Potencialmente mejor rendimiento para el código de despacho basado en cadenas.

DESVENTAJA MAYOR: siempre hay un costo.

Cierta complejidad de implementación y prueba aumentada para el compilador.

ALTERNATIVAS: ¿Se pueden obtener los beneficios y ventajas de alguna manera sin un cambio de idioma?

No; Las pruebas encadenadas de if-then-else para la igualdad de cadenas son potencialmente costosas y la introducción de una enumeración para sus constantes conmutables, una por valor de cadena de interés, agregaría otro tipo a un programa sin una buena causa ...


la parte audaz es bastante sorprendente
Simon Bergot el

1
@Simon bien para mí personalmente, se lee como un trato indirecto, "perderemos la competencia a C # si continuamos con las formas anteriores a Java5 de tratar con consideraciones como esa". :) Para ver un ejemplo de "formas anteriores a Java5", consulte JDK-1223179: encienda las cadenas , enviado en 1995 y cerrado rápidamente como No soluciona : "No contenga la respiración. Nada parecido a esto está en nuestros planes ".
mosquito

Gracias, muy interesante por ver los motivos expuestos en la propuesta. Todavía se siente mal decir que estamos introduciendo un tipo a un programa "sin una buena causa": ¡somos programadores OO! :)
otradave

55
@anotherdave "orientado a objetos" justifica la introducción de tipos solo cuando estos tienen un propósito significativo. Aparentemente, la opinión predominante en JCP resultó que el uso de enumeraciones como envolturas sin cerebro para las constantes de cadena en el interruptor no califica como significativo
mosquito

1
Wow, estoy sorprendido (en el buen sentido) de ver la propuesta oficial contrarrestando activamente la hinchazón tipo. Eso es refrescante. El tipo hinchado es un gran problema en Java.
Ben Lee

7

Además de hacer que el código sea más legible, hay posibles ganancias de rendimiento en relación con las if/else ifcomparaciones. Si el cambio vale la pena depende de cuántas comparaciones estaría haciendo. Se emitirá un interruptor de cadena como dos instrucciones de interruptor separadas. El primero opera con códigos hash, por lo que tiende a ser una complejidad lookupswitchque finalmente genera O(log n). El segundo siempre es perfecto O(1) tableswitch, por lo que la complejidad combinada sigue siendo O(log n). Una sola cadena lineal de if/else ifdeclaraciones daría una O(n)complejidad ligeramente peor .

Si está comparando más de, digamos, tres cadenas, entonces a switches probablemente más legible y compacto. Es probable que funcione mejor, aunque es poco probable que note una diferencia a menos que esté haciendo una gran cantidad de comparaciones en una ruta de código dinámico.


1
Sin embargo, estaba más preguntando por qué usaría un interruptor en una cadena en lugar de un interruptor en una enumeración. Consideraría una if/elsemala práctica de un bloque grande , pero por el momento, no tendría muchas razones para usar una.
otraveve

Pero luego, un Mapa en combinación con el patrón de comando incluso produciría más legibilidad con la misma complejidad porque tienes el tipo adicional del comando
SpaceTrucker

3

El cambio de cadenas podría usarse cuando sus enumvalores provienen del exterior, es decir, almacenados en una base de datos.

Otra cosa notable en JDK 7 switches que es mucho más perfumante que las if-elseconstrucciones.

Y un buen caso de uso para cadenas rápidas switchpodría ser el análisis de flujo JSON / XML cuando necesita hacer muchos cambios en los tipos de nodo y atributo. No puedo pensar en una mejor opción para esto.


1
"El cambio de cadenas es insustituible cuando los valores de su enumeración provienen del exterior, es decir, se almacenan en una base de datos": ¿Puede explicar esto? Las cadenas en la declaración de cambio están codificadas: tan pronto como se cambian las cadenas en la base de datos, su código está desactualizado.
Giorgio

Bueno, tiene razón: enumse pueden usar s en este caso debido a la naturaleza estática de Java. Cuando estaba escribiendo esto, estaba pensando en una Rolede una biblioteca de seguridad que generalmente se proporciona como una clase y no se puede incluir enum. Otro caso es un código Java / Groovy compilado dinámicamente; en esta situación, que es rara, los conmutadores de cadena podrían ser una mejor opción.
Andrey Chaschev

2

Sencillez

La compatibilidad con String in Switch es útil para procesar datos sin conversión a enumeración o if-elselógica. A veces es más fácil activar String.

De la propuesta de características en la lista de correo JDK 7 (proyecto Coin) ( @gnat answer )

La introducción de una enumeración para sus constantes conmutables, una por valor de cadena de interés, agregaría otro tipo a un programa sin una buena causa ...

Versión If-Else

Esto es corto, pero muchos if'sson difíciles de leer. Y esto es lento.

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

Versión Enum

Las enumeraciones deben definirse, esto es bueno, pero a veces no es necesario.

enum Color {RED, GREEN}

Procesando como siempre

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7: cadenas en la versión de declaraciones de conmutador

Podemos procesar sin convertir y definir tipos adicionales.

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}

77
Sin embargo, esto no responde a la pregunta: ¿por qué usaría cadenas en lugar de enumeraciones aquí?
Dave Newton el

0

La mayoría de las mejoras en cualquier idioma son para hacer que el código sea más fácil de leer. Estoy a favor del código legible sobre el elegante cualquier día.

Puede que no lo creas, pero prueba:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);

No estoy claro en su ejemplo de código frente a sus comentarios anteriores. ¿Te refieres a Enum como un ejemplo de algo difícil de leer?
otradave


2
Esto es muy artificial; finges que la enumeración no tendría un campo de correo electrónico, o que esto no sería una clase.
Dave Newton el

44
@ user2860598 Si está tratando de hacer un punto, use un ejemplo que sea relevante. Tampoco aborda la digitación gorda de una constante de cadena.
Dave Newton el

1
@ user2860598 La respuesta que vinculó es que se han introducido y que anteriormente podrían "aproximarse" con una Enum. Mi punto era que el uso de Enum parece preferible aún, incluso con su introducción.
otradave

0

Las enumeraciones son geniales y debe usarlas en lugar de cadenas cuando tenga la capacidad de hacerlo. Pero hay algunas ocasiones en las que simplemente no puede, por ejemplo, cuando necesita trabajar con algún objeto externo que proviene de fuera de Java. Imagina que tienes que analizar algo. Al igual que la respuesta del servidor, la configuración, el archivo de registro o algo similar: tiene un montón de opciones que está buscando y no hay forma de que puedan ser enumeraciones. Entonces en Java <7 estarías atrapado con un montón de

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

Todavía puede usar enumeraciones en este caso simplemente tratando de obtenerlas por nombres y / o proporcionando una cadena personalizada-> rutina de enumeración, pero a veces no es posible o simplemente no es práctico (es decir, cuando tendría que crear demasiadas enumeraciones)

TLDR : absolutamente debe usar Enums cuando trabaja puramente con código Java, pero no siempre es posible con objetos externos. Espero que mi explicación tenga sentido.


Si está tratando con datos externos y ya sabe lo suficiente como para saber lo que necesita en sus ifdeclaraciones, entonces debería estar resumiendo de todos modos , lo que significa que aún podría usar enumeraciones o un patrón de comando, etc.
Dave Newton

@DaveNewton sí, todavía puedes usar enumeraciones, pero como dije en mi respuesta, a veces no es práctico, como en el caso de que termines creando una lista de enumeraciones solo para usar una vez en tu código durante el análisis.

@dimoniy Pero si tuviera que crear cientos de valores de Enum, ¿no significaría que con una alternativa de cambio tendría que tener cientos de declaraciones de casos? Si hay tantas variables, definitivamente preferiría la seguridad de tipo de las enumeraciones.
otradave

0

No estoy de acuerdo con la opinión de que es un código más limpio y legible cuando lo usas Stringsen declaraciones de cambio y piensas que es una mala práctica de programación. Si cambia el valor que usa para almacenar, tiene que cambiarlo cada vez que cambie o si ocurre. Esto no es bueno ya que está poniendo valores codificados en cada bir de su código. ¿Qué vas a hacer si algún día decides cambiar uno de estos valores codificados? ¿Buscar y reemplazar cada copia?

Si tiene algunos valores codificados que hace declaraciones if-elseif, usar valores primitivos constantes para ellos es mucho mejor antes de Java 1.5 solo porque brinda seguridad de tipo.

OK, habrá situaciones en las que obtendrás valores de cadena (de solicitud HTTP, archivos, etc.) y convertirlos a los valores primitivos es muy doloroso. Pero Enumhacemos un buen trabajo en este punto. Porque cuando desee cambiar el valor que almacena en Enum, simplemente cámbielo cuando declare. No hay necesidad de cambiar nada más en su código. (Por supuesto, debe cambiar los valores almacenados en otro lugar).

Por supuesto, si solo está implementando un código sucio y vago, es perfecto. No desea involucrar codificar muchos Enums, pero en un software complejo a gran escala que lo matará.


-1

Si sabe qué información ingresa y que solo puede ser de 5 estados, utilice un Enum. Sin embargo, si los posibles estados podrían ser superiores a 9000 y solo necesita encontrar 42, entonces usar un interruptor es mejor porque no desea escribir todos esos estados.

Un Enum tiende a ser la elección de la mayoría en la mayoría de las circunstancias, a menos que los posibles estados sean desconocidos o haya muchos y solo le importen unos pocos.

¿Pero por qué lo presentaron ahora? Fue solo un cambio que permitió un código más limpio.

En 1.5 también le permitieron crear cuerpos personalizados para Enums.


¿Pero no asignarías los otros 8958 valores posibles al único estado Enum?
otradave

@anotherdave Aquí es donde el defaulten switchviene a jugar. No sé si puede tener un estado predeterminado Enum, a menos que establezca un estado predeterminado, pero luego este código simplemente se hincha, mientras que a switches mucho más limpio de usar.

3
Parece extraño decir que un UNKNOWNestado en un Enum es hinchado, pero un defaultcaso en un interruptor no lo es.
otraveve
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.