Quiero agregar valores a un HashMap
, que sería usado por métodos en el misma clase. Tengo dos soluciones:
- Agregar todos los valores con
static
- Cuando se llame al primer método, agregue los valores
Solución n. ° 1:
private static Map<Character, String> codes = new HashMap<>(); static { codes.put("A", ".-"); codes.put("B", "-..."); codes.put("C", "-.-."); codes.put("D", "-.."); codes.put("E", "."); codes.put("F", "..-."); // ... }
Solución n. ° 2:
boolean methodIsCalled = false; public static char decode(String s) { if(!methodIsCalled) { addValues(); methodIsCalled = true; } // ... } private static void addValues() { codes.put("A", ".-"); codes.put("B", "-..."); codes.put("C", "-.-."); codes.put("D", "-.."); codes.put("E", "."); codes.put("F", "..-."); // ... }
¿Cuál es el más eficiente? ¿Cuál es la mejor práctica?
Comentarios
- ¿Por qué estás poniendo eso en un HashMap en primer lugar? ¿Por qué no una matriz de 26 cadenas?
- ¿Cómo resuelve este problema una matriz de 26 cadenas? En particular, ¿cómo se hace el mapeo? ¿Tiene la conversión implícita de A – > 0, B – > 0, …, en mente?
- @Ali una matriz final maneja la inmutabilidad y la inicialización. A- > 0, B- > 1 lo hace bastante bien evitando muchos de los otros problemas de otras bibliotecas necesarias, bloques estáticos adicionales o constructores. Es ' claro y razonable.
- @MichaelT Tal vez para este ejemplo en particular, dado que el usuario quiere tener un mapeo para el código morse, una matriz de String de tamaño 26 está bien, sin embargo, no es una solución general. Mi respuesta fue hacia una solución general, no esta en particular. En muchos casos, el dominio es tan grande que no podemos usar un mapeo directo a enteros y necesitamos usar un hashmap.
- @MichaelT por cierto, una matriz solo es inmutable en cuanto a tamaño, pero puedes cambiar uno de sus elementos. a [0] = " new val ".
Responder
Su solución 1 puede ser problemática, ya que el mapa de hash es estático y se inicializará solo una vez, y todas las instancias de su clase lo comparten. ¿Es este su comportamiento previsto o desea que cada instancia tenga su propio mapa? Si solo tiene un mapa, sugeriría pasar el conjunto al constructor en lugar de usar uno estático, por ejemplo:
public class Data { private final Map<Character, String> codes; public Data(Map<Character, String> codes) { this.codes = codes} }
Su solución 2 agrega la sobrecarga de la inicialización perezosa del conjunto, cada vez que lo necesite, y agrega el cheque feo methodIsCalled
a la lógica de su programa. Creo que iniciar el mapa en el constructor es una mejor opción.
public class Data { private final Map<Character, String> codes; public Data() { this.codes = new HashMap<>(); codes.put("A", ".-"); codes.put("B", "-..."); codes.put("C", "-.-."); codes.put("D", "-.."); codes.put("E", "."); codes.put("F", "..-."); } }
La otra pregunta que debes responder es que si cambias los valores de este hashmap más tarde O no. Si no lo cambia, es mejor que busque hashMaps inmutables. Una opción es usar Collections.unmodifiableMap (mapa).
También puede usar las bibliotecas de Google Guava para que le permitan inicializar un mapa en una línea y obtenga un mapa inmutable:
ImmutableMap.<Character, String>builder() .put("A", ".-") .put("B", "-...") .put("C", "-.-.") .put("D", "-..") .put("E", ".") .put("F", "..-.") .build();
Respuesta
Nada puede vencer ImmutableMap de Guava con su consumo de memoria optimizado, pero aquí hay un par de soluciones puras:
/* Name of the class has to be "Main" only if the class is public. */ class Ideone { private static final Map<Character, String> codes1; static { Map<Character, String> temp= new HashMap<Character, String>(); temp.put("A", ".-"); temp.put("B", "-..."); temp.put("C", "-.-."); temp.put("D", "-.."); temp.put("E", "."); temp.put("F", "..-."); // ... codes1 = Collections.unmodifiableMap(temp); } private static final Map<Character, String> codes2 = Collections.unmodifiableMap(new HashMap<Character, String>() { { put("A", ".-"); put("B", "-..."); put("C", "-.-."); put("D", "-.."); put("E", "."); put("F", "..-."); // ... } }); }
Respuesta
Si no insiste en la inicialización diferida (y para un mapa pequeño que no crece de 26 elementos, no debería hacerlo), ¿por qué no optimizar la legibilidad? Siempre usaría algo como
private static Map<Character, String> codes = newMap( "A", ".-", "B", "-...", "C", "-.-.", ... );
(con una función auxiliar adecuadamente definida newMap
).
Comentarios
- ¿Puedes incluso escribir newMap con paquetes de parámetros?
- @ VF1 Puedes, si lo defines como una función genérica con varargs .
Responder
En estos casos, supongo que la pregunta no se trata de un método eficiente, sino de cuándo realmente necesita ese mapa inicializado y listo ..
en el caso de la inicialización estática – para cuando se cargue la clase
su enfoque de carga diferida puede ser necesario si necesita establecer «enorme «map, y digamos que a menudo esos valores provienen de una fuente costosa (es decir, a través de la red), incluso entonces es posible que no necesite una marca externa.
Collection.isEmpty () le diría si ya se ha inicializado o no (siempre que, por supuesto, haya al menos un valor para inicializarlo)