Mientras trabajaba recientemente en una gran empresa, noté que los programadores seguían este estilo de codificación:
Supongamos que tengo una función que devuelve 12 si la entrada es A, 21 si la entrada es B y 45 si la entrada es C.
Entonces puedo escribir la firma de la función como:
int foo(String s){
if(s.equals("A")) return 12;
else if(s.equals("B")) return 21;
else if(s.equals("C")) return 45;
else throw new RuntimeException("Invalid input to function foo");
}
Pero en la revisión del código me pidieron que cambiara la función a la siguiente:
int foo(String s){
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("A", 12);
map.put("B", 21);
map.put("C", 45);
return map.get(s);
}
No puedo convencerme de por qué el segundo código es mejor que el primero. El segundo código definitivamente tomaría más tiempo en ejecutarse.
La única razón para usar el segundo código puede ser que ofrece una mejor legibilidad. Pero si la función se llama muchas veces, ¿la segunda función no ralentizaría el tiempo de ejecución de la utilidad que la llama?
¿Qué piensas sobre esto?
coding-style
coding-standards
Nikunj Banka
fuente
fuente
switch
parece más apropiado queif-else
). Pero en algún momento, se vuelve problemático. La principal ventaja de usar un Mapa es que puede cargarlo desde un archivo o una tabla, etc. Si está codificando la entrada al mapa, no veo mucho valor en un interruptor.Respuestas:
El punto es mover la creación del hashmap fuera de la función y hacerlo una vez (o solo menos veces que de otra manera).
Sin embargo, java desde java7 ha podido tener cadenas (finales) en los conmutadores:
fuente
En su segundo ejemplo,
Map
debe ser un miembro estático privado para evitar la sobrecarga de inicialización redundante.Para grandes cantidades de valores, el mapa funcionará mejor. Usando una tabla hash, uno puede buscar la respuesta en tiempo constante. La construcción de if múltiple tiene que comparar la entrada con cada una de las posibilidades hasta que encuentre la respuesta correcta.
En otras palabras, la búsqueda del mapa es O (1) mientras que
if
s son O (n) donde n es el número de entradas posibles.La creación del mapa es O (n), pero solo se realiza una vez si es un estado constante estático. Para una búsqueda realizada con frecuencia, el mapa superará a las
if
declaraciones a largo plazo, a costa de un poco más de tiempo cuando se inicia el programa (o la clase se carga, según el idioma).Dicho esto, el mapa no siempre es la herramienta adecuada para este trabajo. Es bueno cuando hay muchos valores, o los valores deben ser configurables a través de un archivo de texto, entrada del usuario o base de datos (en cuyo caso el mapa actúa como caché).
fuente
Hay dos velocidades en el software: el tiempo que lleva escribir / leer / depurar el código; y el tiempo que lleva ejecutar el código.
Si puede convencerme (y a sus revisores de código) de que la función hashmap es realmente más lenta que if / then / else (después de refactorizar para hacer un hashmap estático) Y puede convencerme / revisores de que se ha llamado suficientes veces para hacer un real diferencia, luego continúe y reemplace el hashmap con el if / else.
De lo contrario, el código hashmap es legible por completo; y (probablemente) libre de errores; puedes determinar eso rápidamente con solo mirarlo. Realmente no se puede decir lo mismo sobre el if / else sin realmente estudiarlo; la diferencia es aún más exagerada cuando hay cientos de opciones.
fuente
Prefiero la respuesta de estilo HashMap.
Hay una métrica para esto
Hay una métrica de calidad de código llamada Complejidad ciclomática . Esta métrica básicamente cuenta el número de rutas diferentes a través del código ( cómo calcular la Complejidad Ciclomática ).
Para cada ruta de ejecución posible, un método se vuelve cada vez más difícil de comprender Y probar completamente para su corrección.
Se reduce al hecho de que "palabras clave de control" como: ifs, elses, whiles, etc ... aprovechan las pruebas booleanas que pueden estar equivocadas. El uso repetido de "palabras clave de control" produce código frágil.
Beneficios adicionales
Además, el "enfoque basado en mapas" alienta a los desarrolladores a pensar en los pares de entrada-salida como un conjunto de datos que se puede extraer, reutilizar, manipular en tiempo de ejecución, probar y verificar. Por ejemplo, a continuación reescribí "foo" para que no estemos permanentemente encerrados en "A-> 12, B-> 21, C-> 45":
rachet_freak menciona este tipo de refactor en su respuesta, argumenta a favor de la velocidad y la reutilización, estoy defendiendo la flexibilidad en el tiempo de ejecución (aunque usar una colección inmutable puede tener enormes beneficios dependiendo de la situación)
fuente
Los datos son mejores que el código. No menos importante porque es demasiado tentador agregar otra rama al código, pero agregar una fila a una tabla es difícil de equivocar. Esta pregunta es una pequeña instancia de esto. Estás escribiendo una tabla de búsqueda. Escriba una implementación, complete con lógica y documentación condicional, o escriba la tabla y luego búsquela.
Una tabla de datos es siempre una mejor representación de algunos datos que el código, pasa la optimización del módulo. Lo difícil que es expresar la tabla puede depender del lenguaje: no conozco Java, pero espero que pueda implementar una tabla de búsqueda más simple que el ejemplo en el OP.
Esta es una tabla de búsqueda en python. Si esto se considera un conflicto atractivo, tenga en cuenta que la pregunta no está etiquetada como Java, la refactorización es independiente del lenguaje y que la mayoría de las personas no conocen Java.
La idea de reestructurar el código para reducir el tiempo de ejecución tiene mérito, pero prefiero usar un compilador que incorpore la configuración común que hacerlo yo mismo.
fuente