En general, Mapa es una estructura de datos que consta de un conjunto de valor clave pares, y cada clave solo puede aparecer una vez en el mapa. Esta publicación resume las 9 preguntas más frecuentes sobre cómo usar Java Mapa y sus clases implementadas. En aras de la simplicidad, usaré genéricos en ejemplos. Por lo tanto, solo escribiré Map
en lugar de específico Map
. Pero siempre puede asumir que tanto el K y V son comparables, lo que significa K extends Comparable
y V extends Comparable
.
0. Convertir un mapa en una lista
En Java, Mapa La interfaz proporciona tres vistas de colección: conjunto de claves, conjunto de valores y conjunto de valores-clave. Todos ellos se pueden convertir a Lista usando un constructor o añadir todo() método. El siguiente fragmento de código muestra cómo construir un Lista de arreglo de un mapa.
// key list List keyList = new ArrayList(map.keySet()); // value list List valueList = new ArrayList(map.values()); // key-value list List entryList = new ArrayList(map.entrySet()); |
1. Iterar sobre un mapa
La iteración sobre cada par de pares clave-valor es la operación más básica para recorrer un mapa. En Java, dicho par se almacena en la entrada del mapa llamada Entrada del mapa. Mapa.entrySet () devuelve un conjunto clave-valor, por lo tanto, la forma más eficiente de revisar cada entrada de un mapa es
for(Entry entry: map.entrySet()) { // get key K key = entry.getKey(); // get value V value = entry.getValue(); } |
El iterador también se puede utilizar, especialmente antes de JDK 1.5
Iterator itr = map.entrySet().iterator(); while(itr.hasNext()) { Entry entry = itr.next(); // get key K key = entry.getKey(); // get value V value = entry.getValue(); } |
2. Ordenar un mapa en las claves
Ordenar un mapa en las claves es otra operación frecuente. Una forma es poner Entrada del mapa en una lista y ordenarlo usando un comparador que ordena el valor.
List list = new ArrayList(map.entrySet()); Collections.sort(list, new Comparator() { @Override public int compare(Entry e1, Entry e2) { return e1.getKey().compareTo(e2.getKey()); } }); |
La otra forma es usar SortedMap, que además proporciona un orden total en sus claves. Por lo tanto, todas las claves deben implementar Comparable o ser aceptado por el comparador.
Una clase de implementación de SortedMap es TreeMap. Su constructor puede aceptar un comparador. El siguiente código muestra cómo transformar un mapa general en un mapa ordenado.
SortedMap sortedMap = new TreeMap(new Comparator() { @Override public int compare(K k1, K k2) { return k1.compareTo(k2); } }); sortedMap.putAll(map); |
3. Ordene un mapa según los valores
Poner el mapa en una lista y ordenarlo también funciona en este caso, pero necesitamos comparar Entrada.getValue () esta vez. El siguiente código es casi el mismo que antes.
List list = new ArrayList(map.entrySet()); Collections.sort(list, new Comparator() { @Override public int compare(Entry e1, Entry e2) { return e1.getValue().compareTo(e2.getValue()); } }); |
Todavía podemos usar un mapa ordenado para esta pregunta, pero solo si los valores también son únicos. Bajo tal condición, puede invertir el par clave = valor a valor = clave. Esta solución tiene una limitación muy fuerte, por lo tanto, no la recomiendo realmente.
4. Inicialice un mapa estático / inmutable
Cuando espera que un mapa permanezca constante, es una buena práctica copiarlo en un mapa inmutable. Estas técnicas de programación defensiva le ayudarán a crear mapas de subprocesos no solo seguros para su uso, sino también seguros.
Para inicializar un mapa estático / inmutable, podemos usar un inicializador estático (como a continuación). El problema de este código es que, aunque mapa se declara como final estática, todavía podemos operarlo después de la inicialización, como Test.map.put(3,"three");
. Por tanto, no es realmente inmutable. Para crear un mapa inmutable usando un inicializador estático, necesitamos una clase anónima adicional y la copiamos en un mapa no modificable en el último paso de la inicialización. Consulte la segunda parte del código. Entonces, un UnsupportedOperationException será arrojado si corres Test.map.put(3,"three");
.
public class Test { private static final Map map; static { map = new HashMap(); map.put(1, "one"); map.put(2, "two"); } } public class Test { private static final Map map; static { Map aMap = new HashMap(); aMap.put(1, "one"); aMap.put(2, "two"); map = Collections.unmodifiableMap(aMap); } } |
Guayaba las bibliotecas también admiten diferentes formas de intilizar una colección estática e inmutable. Para obtener más información sobre los beneficios de las utilidades de recolección inmutables de Guava, consulte Colecciones inmutables explicadas en la guía del usuario de Guava.
5. Diferencia entre HashMap, TreeMap y Hashtable
Hay tres implementaciones principales de Mapa interfaz en Java: HashMap, TreeMap, y Tabla de picadillo. Las diferencias más importantes incluyen:
- El orden de iteración. HashMap y Tabla de picadillo no garantice el orden del mapa; en particular, no garantizan que el pedido se mantenga constante en el tiempo. Pero TreeMap iterará todas las entradas según el «orden natural» de las claves o mediante un comparador.
- valor clave permiso. HashMap permite nulo clave y nulo valores (solo se permite una clave nula porque no se permiten dos claves iguales). Tabla de picadillo no permite nulo clave o nulo valores. Si TreeMap utiliza ordenamiento natural o su comparador no permite nulo claves, se lanzará una excepción.
- Sincronizado. Solo Tabla de picadillo está sincronizado, otros no. Por lo tanto, «si no se necesita una implementación segura para subprocesos, se recomienda utilizar HashMap en lugar de Tabla de picadillo. «
Una comparación más completa es
| HashMap | Hashtable | TreeMap ------------------------------------------------------- iteration order | no | no | yes null key-value | yes-yes | no-no | no-yes synchronized | no | yes | no time performance | O(1) | O(1) | O(log n) implementation | buckets | buckets | red-black tree
Lea más sobre HashMap frente a TreeMap frente a Hashtable frente a LinkedHashMap.
6. Un mapa con vista / búsqueda inversa
A veces, necesitamos un conjunto de pares clave-clave, lo que significa que los valores del mapa son únicos, así como las claves (mapa uno a uno). Esta restricción permite crear una «vista / búsqueda inversa» de un mapa. Entonces podemos buscar una clave por su valor. Tal estructura de datos se llama mapa bidireccional, que lamentablemente no es compatible con JDK.
Tanto Apache Common Collections como Guava proporcionan la implementación de un mapa bidireccional, llamado BidiMap y BiMap, respectivamente. Ambos aplican la restricción de que existe una relación 1: 1 entre claves y valores.
7. Copia superficial de un mapa
La mayor parte de la implementación de un mapa en Java, si no todas, proporciona un constructor de copia de otro mapa. Pero el procedimiento de copia es no sincronizado. Eso significa que cuando un hilo copia un mapa, otro puede modificarlo estructuralmente. Para[evitarunacopiaaccidentalnosincronizadasedebeusar[preventaccidentalunsynchronizedcopyoneshoulduseColecciones.SynchronizedMap () por adelantado.
Map copiedMap = Collections.synchronizedMap(map); |
Otra forma interesante de copia superficial es mediante el uso de clon() método. sin embargo lo és NO incluso recomendado por el diseñador del marco de la colección de Java, Josh Bloch. En una conversación sobre «Copiar constructor versus clonación«, él dijo
A menudo proporciono un método de clonación pública en clases concretas porque la gente lo espera. … Es una pena que Cloneable esté roto, pero sucede. … Cloneable es un punto débil, y creo que la gente debería ser consciente de sus limitaciones.
Por esta razón, ni siquiera te diré cómo usar clon() método para copiar un mapa.
8. Crea un mapa vacío
Si el mapa es inmutable, use
map = Collections.emptyMap(); |
De lo contrario, use cualquier implementación. Por ejemplo
map = new HashMap(); |
EL FIN