Buscar..


Introducción

La interfaz java.util.Map representa una asignación entre las claves y sus valores. Un mapa no puede contener claves duplicadas; y cada clave puede asignarse a un máximo de un valor.

Como Map es una interfaz, entonces necesita crear una instancia de una implementación concreta de esa interfaz para poder usarla; hay varias implementaciones de Map , y en su mayoría se utilizan java.util.HashMap y java.util.TreeMap

Observaciones

Un mapa es un objeto que almacena claves con un valor asociado para cada clave. Una clave y su valor a veces se llaman un par clave / valor o una entrada . Los mapas suelen proporcionar estas características:

  • Los datos se almacenan en el mapa en pares clave / valor.
  • El mapa puede contener solo una entrada para una clave en particular. Si un mapa contiene una entrada con una clave particular e intenta almacenar una segunda entrada con la misma clave, la segunda entrada reemplazará a la primera. En otras palabras, esto cambiará el valor asociado con la clave.
  • Los mapas proporcionan operaciones rápidas para probar si existe una clave en el mapa, para recuperar el valor asociado con una clave y para eliminar un par de clave / valor.

La implementación de mapa más utilizada es HashMap . Funciona bien con teclas que son cadenas o números.

Los mapas simples como HashMap no están ordenados. Iterar a través de pares clave / valor puede devolver entradas individuales en cualquier orden. Si necesita recorrer de forma controlada las entradas del mapa, debe mirar lo siguiente:

  • Los mapas ordenados , como TreeMap , recorrerán las claves en su orden natural (o en un orden que puede especificar, al proporcionar un Comparador ). Por ejemplo, se esperaría que un mapa ordenado que usa números como claves itere a través de sus entradas en orden numérico.

  • LinkedHashMap permite iterar a través de entradas en el mismo orden en que se insertaron en el mapa, o por el orden de acceso más reciente.

Agregar un elemento

  1. Adición
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element."); 
System.out.println(map.get(1));

Salida: First element.

  1. Anular
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
map.put(1, "New element.");
System.out.println(map.get(1));

Salida: New element.

HashMap se utiliza como ejemplo. También se pueden usar otras implementaciones que implementan la interfaz de Map .

Añadir varios elementos

Podemos usar V put(K key,V value) :

Asocia el valor especificado con la clave especificada en este mapa (operación opcional). Si el mapa contenía previamente una asignación para la clave, el valor anterior se reemplaza por el valor especificado.

String currentVal;
Map<Integer, String> map = new TreeMap<>();
currentVal = map.put(1, "First element.");
System.out.println(currentVal);// Will print null
currentVal = map.put(2, "Second element.");
System.out.println(currentVal); // Will print null yet again    
currentVal = map.put(2, "This will replace 'Second element'");
System.out.println(currentVal); // will print Second element.
System.out.println(map.size()); // Will print 2 as key having
// value 2 was replaced.

Map<Integer, String> map2 = new HashMap<>();
map2.put(2, "Element 2");
map2.put(3, "Element 3");

map.putAll(map2);

System.out.println(map.size());  

Salida:

3

Para agregar muchos artículos puedes usar una clase interna como esta:

Map<Integer, String> map = new HashMap<>() {{
    // This is now an anonymous inner class with an unnamed instance constructor
    put(5, "high");
    put(4, "low");
    put(1, "too slow");
}};

Tenga en cuenta que crear una clase interna anónima no siempre es eficiente y puede provocar pérdidas de memoria, por lo que, cuando sea posible, use un bloque de inicialización en su lugar:

static Map<Integer, String> map = new HashMap<>();

static {
    // Now no inner classes are created so we can avoid memory leaks
    put(5, "high");
    put(4, "low");
    put(1, "too slow");
}

El ejemplo anterior hace que el mapa sea estático. También se puede utilizar en un contexto no estático eliminando todas las apariciones de static .

Además de que la mayoría de las implementaciones son compatibles con putAll , que puede agregar todas las entradas de un mapa a otro de esta manera:

another.putAll(one);

Usando métodos de mapa predeterminados desde Java 8

Ejemplos de uso de métodos predeterminados introducidos en Java 8 en la interfaz del mapa

  1. Utilizando getOrDefault

Devuelve el valor asignado a la clave, o si la clave no está presente, devuelve el valor predeterminado

Map<Integer, String> map = new HashMap<>();
map.put(1, "First element");
map.get(1);                                 // => First element
map.get(2);                                 // => null
map.getOrDefault(2, "Default element");     // => Default element
  1. Usando forEach

Permite realizar la operación especificada en la 'acción' en cada entrada de mapa

  Map<Integer, String> map = new HashMap<Integer, String>();
  map.put(1, "one");
  map.put(2, "two");
  map.put(3, "three");
  map.forEach((key, value) -> System.out.println("Key: "+key+ " :: Value: "+value));

   // Key: 1 :: Value: one
   // Key: 2 :: Value: two
   // Key: 3 :: Value: three
  1. Usando replaceAll

Reemplazará con nuevo valor solo si la clave está presente

 Map<String, Integer> map = new HashMap<String, Integer>();
 map.put("john", 20);
 map.put("paul", 30);
 map.put("peter", 40);
 map.replaceAll((key,value)->value+10);   //{john=30, paul=40, peter=50}
  1. Usando putIfAbsent

El par clave-valor se agrega al mapa, si la clave no está presente o asignada a nulo

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.putIfAbsent("kelly", 50);     //{john=20, paul=30, peter=40, kelly=50}
  1. Utilizando eliminar

    Elimina la clave solo si está asociada con el valor dado

     Map<String, Integer> map = new HashMap<String, Integer>();
     map.put("john", 20);
     map.put("paul", 30);
     map.put("peter", 40);
     map.remove("peter",40); //{john=30, paul=40}
    
  2. Usando reemplazar

    Si la clave está presente, el valor se reemplaza por un nuevo valor. Si la llave no está presente, no hace nada.

Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.replace("peter",50); //{john=20, paul=30, peter=50}
map.replace("jack",60); //{john=20, paul=30, peter=50}
  1. Usando computeIfAbsent

Este método agrega una entrada en el mapa. la clave se especifica en la función y el valor es el resultado de la aplicación de la función de mapeo

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.computeIfAbsent("kelly", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30}
    map.computeIfAbsent("peter", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30} //peter already present
  1. Usando computeIfPresent

Este método agrega una entrada o modifica una entrada existente en el Mapa. No hace nada si una entrada con esa clave no está presente.

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.computeIfPresent("kelly", (k,v)->v+10); //{john=20, paul=30, peter=40} //kelly not present
    map.computeIfPresent("peter", (k,v)->v+10); //{john=20, paul=30, peter=50} // peter present, so increase the value 
  1. Utilizando compute

Este método reemplaza el valor de una clave por el valor recién calculado

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.compute("peter", (k,v)->v+50); //{john=20, paul=30, peter=90} //Increase the value 
  1. Usando fusionar

Agrega el par clave-valor al mapa, si la clave no está presente o el valor de la clave es nulo Reemplaza el valor con el valor recién calculado, si la clave está presente La clave se elimina del mapa, si el nuevo valor calculado es nulo

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    
    //Adds the key-value pair to the map, if key is not present or value for the key is null
    map.merge("kelly", 50 , (k,v)->map.get("john")+10); // {john=20, paul=30, peter=40, kelly=50}
    
    //Replaces the value with the newly computed value, if the key is present
    map.merge("peter", 50 , (k,v)->map.get("john")+10); //{john=20, paul=30, peter=30, kelly=50}
   
    //Key is removed from the map , if new value computed is null
    map.merge("peter", 30 , (k,v)->map.get("nancy")); //{john=20, paul=30, kelly=50}

Borrar el mapa

Map<Integer, String> map = new HashMap<>();

map.put(1, "First element.");
map.put(2, "Second element.");
map.put(3, "Third element.");

map.clear();

System.out.println(map.size());   // => 0

Iterando a través de los contenidos de un Mapa.

Los mapas proporcionan métodos que le permiten acceder a las claves, valores o pares clave-valor del mapa como colecciones. Puedes recorrer estas colecciones. Dado el siguiente mapa por ejemplo:

Map<String, Integer> repMap = new HashMap<>();
repMap.put("Jon Skeet", 927_654);
repMap.put("BalusC", 708_826);
repMap.put("Darin Dimitrov", 715_567);

Iterando a través de las teclas del mapa:

for (String key : repMap.keySet()) {
    System.out.println(key);
}

Huellas dactilares:

Darin Dimitrov
Jon Skeet
Balus

keySet() proporciona las claves del mapa como un Set . Set se utiliza porque las claves no pueden contener valores duplicados. Iterando a través del conjunto produce cada tecla a su vez. Los HashMaps no se ordenan, por lo que en este ejemplo, las claves se pueden devolver en cualquier orden.

Iterando a través de los valores del mapa:

for (Integer value : repMap.values()) {
    System.out.println(value);
}

Huellas dactilares:

715567
927654
708826

values() devuelve los valores del mapa como una Collection . Iterando a través de la colección produce cada valor a su vez. Nuevamente, los valores pueden ser devueltos en cualquier orden.

Iterando a través de claves y valores juntos.

for (Map.Entry<String, Integer> entry : repMap.entrySet()) {
    System.out.printf("%s = %d\n", entry.getKey(), entry.getValue());
}

Huellas dactilares:

Darin Dimitrov = 715567
Jon Skeet = 927654
BalusC = 708826

entrySet() devuelve una colección de objetos Map.Entry . Map.Entry da acceso a la clave y al valor de cada entrada.

Fusionar, combinar y componer mapas.

Use putAll para poner a cada miembro de un mapa en otro. Las claves ya presentes en el mapa tendrán sus valores correspondientes sobrescritos.

Map<String, Integer> numbers = new HashMap<>();
numbers.put("One", 1)
numbers.put("Three", 3)
Map<String, Integer> other_numbers = new HashMap<>();
other_numbers.put("Two", 2)
other_numbers.put("Three", 4)

numbers.putAll(other_numbers)

Esto produce el siguiente mapeo en numbers :

"One" -> 1
"Two" -> 2
"Three" -> 4 //old value 3 was overwritten by new value 4

Si desea combinar valores en lugar de sobrescribirlos, puede usar Map.merge , agregado en Java 8, que utiliza un BiFunction proporcionado por el BiFunction para combinar valores para claves duplicadas. merge funciona con claves y valores individuales, por lo que deberá usar un bucle o Map.forEach . Aquí concatenamos cadenas para claves duplicadas:

for (Map.Entry<String, Integer> e : other_numbers.entrySet())
    numbers.merge(e.getKey(), e.getValue(), Integer::sum);
//or instead of the above loop
other_numbers.forEach((k, v) -> numbers.merge(k, v, Integer::sum));

Si desea aplicar la restricción, no hay claves duplicadas, puede usar una función de combinación que lanza un AssertionError :

mapA.forEach((k, v) ->
    mapB.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

Componiendo el Mapa <X, Y> y el Mapa <Y, Z> para obtener el Mapa <X, Z>

Si desea componer dos asignaciones, puede hacerlo de la siguiente manera

    Map<String, Integer> map1 = new HashMap<String, Integer>();
    map1.put("key1", 1);
    map1.put("key2", 2);
    map1.put("key3", 3);
    
    Map<Integer, Double> map2 = new HashMap<Integer, Double>();
    map2.put(1, 1.0);
    map2.put(2, 2.0);
    map2.put(3, 3.0);

    Map<String, Double> map3 = new new HashMap<String, Double>();
    map1.forEach((key,value)->map3.put(key,map2.get(value)));

Esto produce el siguiente mapeo

    "key1" -> 1.0
    "key2" -> 2.0
    "key3" -> 3.0

Comprobar si existe la clave

Map<String, String> num = new HashMap<>();
num.put("one", "first");

if (num.containsKey("one")) {
    System.out.println(num.get("one")); // => first
}

Los mapas pueden contener valores nulos

Para los mapas, hay que tener cuidado de no confundir "que contiene una clave" con "tener un valor". Por ejemplo, HashMap s puede contener null, lo que significa que el siguiente es un comportamiento perfectamente normal:

Map<String, String> map = new HashMap<>();
map.put("one", null);
if (map.containsKey("one")) {
    System.out.println("This prints !"); // This line is reached 
}
if (map.get("one") != null) {
    System.out.println("This is never reached !"); // This line is never reached 
}

Más formalmente, no hay garantía de que map.contains(key) <=> map.get(key)!=null

Iterando entradas de mapa de manera eficiente

Esta sección proporciona código y puntos de referencia para diez implementaciones de ejemplo únicas que repiten las entradas de un Map<Integer, Integer> y generan la suma de los valores de Integer . Todos los ejemplos tienen una complejidad algorítmica de Θ(n) , sin embargo, los puntos de referencia siguen siendo útiles para proporcionar información sobre qué implementaciones son más eficientes en un entorno del "mundo real".

  1. Implementación usando Iterator con Map.Entry
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Integer, Integer> pair = it.next();
        sum += pair.getKey() + pair.getValue();
    }
  1. Implementación utilizando for con Map.Entry
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        sum += pair.getKey() + pair.getValue();
    }
  1. Implementación usando Map.forEach (Java 8+)
    map.forEach((k, v) -> sum[0] += k + v);
  1. Implementación usando Map.keySet con for
    for (Integer key : map.keySet()) {
        sum += key + map.get(key);
    }
  1. Implementación usando Map.keySet con Iterator
    Iterator<Integer> it = map.keySet().iterator();
    while (it.hasNext()) {
        Integer key = it.next();
        sum += key + map.get(key);
    }
  1. Implementación usando for con Iterator y Map.Entry
    for (Iterator<Map.Entry<Integer, Integer>> entries = 
             map.entrySet().iterator(); entries.hasNext(); ) {
        Map.Entry<Integer, Integer> entry = entries.next();
        sum += entry.getKey() + entry.getValue();
    }
  1. Implementación usando Stream.forEach (Java 8+)
    map.entrySet().stream().forEach(e -> sum += e.getKey() + e.getValue());
  1. Implementación usando Stream.forEach con Stream.parallel (Java 8+)
    map.entrySet()
       .stream()
       .parallel()
       .forEach(e -> sum += e.getKey() + e.getValue());
  1. Implementación utilizando IterableMap desde Apache Collections
    MapIterator<Integer, Integer> mit = iterableMap.mapIterator();
    while (mit.hasNext()) {
        sum += mit.next() + it.getValue();
    }
  1. Implementación usando MutableMap de Eclipse Collections
     mutableMap.forEachKeyValue((key, value) -> {
         sum += key + value;
     });

Pruebas de rendimiento ( Código disponible en Github )
Entorno de prueba: Windows 8.1 de 64 bits, Intel i7-4790 3.60GHz, 16 GB

  1. Rendimiento promedio de 10 ensayos (100 elementos) Mejor: 308 ± 21 ns / op

    Benchmark                           Score     Error  Units
    test3_UsingForEachAndJava8            308  ±     21  ns/op
    test10_UsingEclipseMutableMap         309  ±      9  ns/op
    test1_UsingWhileAndMapEntry           380  ±     14  ns/op
    test6_UsingForAndIterator             387  ±     16  ns/op
    test2_UsingForEachAndMapEntry         391  ±     23  ns/op
    test7_UsingJava8StreamAPI             510  ±     14  ns/op
    test9_UsingApacheIterableMap          524  ±      8  ns/op
    test4_UsingKeySetAndForEach           816  ±     26  ns/op
    test5_UsingKeySetAndIterator          863  ±     25  ns/op
    test8_UsingJava8StreamAPIParallel    5552  ±    185  ns/op
    
  2. Rendimiento promedio de 10 ensayos (10000 elementos) Lo mejor: 37.606 ± 0.790 μs / op

    Benchmark                           Score     Error  Units
    test10_UsingEclipseMutableMap       37606  ±    790  ns/op
    test3_UsingForEachAndJava8          50368  ±    887  ns/op
    test6_UsingForAndIterator           50332  ±    507  ns/op
    test2_UsingForEachAndMapEntry       51406  ±   1032  ns/op
    test1_UsingWhileAndMapEntry         52538  ±   2431  ns/op
    test7_UsingJava8StreamAPI           54464  ±    712  ns/op
    test4_UsingKeySetAndForEach         79016  ±  25345  ns/op
    test5_UsingKeySetAndIterator        91105  ±  10220  ns/op
    test8_UsingJava8StreamAPIParallel  112511  ±    365  ns/op
    test9_UsingApacheIterableMap       125714  ±   1935  ns/op
    
  3. Rendimiento promedio de 10 ensayos (100000 elementos) Mejor: 1184.767 ± 332.968 μs / op

    Benchmark                            Score       Error  Units
    test1_UsingWhileAndMapEntry       1184.767  ±  332.968  μs/op
    test10_UsingEclipseMutableMap     1191.735  ±  304.273  μs/op
    test2_UsingForEachAndMapEntry     1205.815  ±  366.043  μs/op
    test6_UsingForAndIterator         1206.873  ±  367.272  μs/op
    test8_UsingJava8StreamAPIParallel 1485.895  ±  233.143  μs/op
    test5_UsingKeySetAndIterator      1540.281  ±  357.497  μs/op
    test4_UsingKeySetAndForEach       1593.342  ±  294.417  μs/op
    test3_UsingForEachAndJava8        1666.296  ±  126.443  μs/op
    test7_UsingJava8StreamAPI         1706.676  ±  436.867  μs/op
    test9_UsingApacheIterableMap      3289.866  ± 1445.564  μs/op
    
  4. Una comparación de las variaciones de rendimiento en relación con el tamaño del mapa

Gráfico de pruebas de rendimiento

       x: Size of Map
    f(x): Benchmark Score (μs/op)

                 100      600     1100     1600     2100
        ---------------------------------------------------
        10  |   0.333    1.631    2.752    5.937    8.024
         3  |   0.309    1.971    4.147    8.147   10.473
         6  |   0.372    2.190    4.470    8.322   10.531
         1  |   0.405    2.237    4.616    8.645   10.707
Tests    2  |   0.376    2.267    4.809    8.403   10.910
 f(x)    7  |   0.473    2.448    5.668    9.790   12.125
         9  |   0.565    2.830    5.952    13.22   16.965
         4  |   0.808    5.012    8.813    13.939  17.407
         5  |   0.81     5.104    8.533    14.064  17.422
         8  |   5.173   12.499   17.351    24.671  30.403

Usar objeto personalizado como clave

Antes de usar su propio objeto como clave, debe anular los métodos hashCode () y equals () de su objeto.

En caso simple tendrías algo como:

class MyKey {
    private String name;
    MyKey(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {            
        if(obj instanceof MyKey) {
            return this.name.equals(((MyKey)obj).name);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
}

hashCode decidirá a qué hash bucket pertenecerá la clave e equals determinará qué objeto dentro de ese hash bucket.

Sin estos métodos, la referencia de su objeto se usará para la comparación anterior que no funcionará a menos que use la misma referencia de objeto cada vez.

Uso de HashMap

HashMap es una implementación de la interfaz de mapa que proporciona una estructura de datos para almacenar datos en pares clave-valor.

1. Declarar HashMap

Map<KeyType, ValueType> myMap = new HashMap<KeyType, ValueType>();

KeyType y ValueType deben ser tipos válidos en Java, como - Cadena, Entero, Flotante o cualquier clase personalizada como Empleado, Estudiante, etc.

Por ejemplo: Map<String,Integer> myMap = new HashMap<String,Integer>();

2. Poner valores en HashMap.

Para poner un valor en HashMap, tenemos que llamar al método put en el objeto HashMap pasando la clave y el valor como parámetros.

myMap.put("key1", 1);
myMap.put("key2", 2);

Si llama al método put con la clave que ya existe en el mapa, el método anulará su valor y devolverá el valor anterior.

3. Obtención de valores de HashMap.

Para obtener el valor de un HashMap, debe llamar al método get , pasando la clave como parámetro.

myMap.get("key1");    //return 1 (class Integer)

Si pasa una clave que no existe en el HashMap, este método devolverá null

4. Compruebe si la clave está en el mapa o no.

myMap.containsKey(varKey);

5. Compruebe si el valor está en el mapa o no.

myMap.containsValue(varValue);

Los métodos anteriores devolverán un valor boolean verdadero o falso si la clave, el valor existe en el Mapa o no.

Creación e inicialización de mapas

Introducción

Maps almacenan pares clave / valor, donde cada clave tiene un valor asociado. Dada una clave particular, el mapa puede buscar el valor asociado muy rápidamente.

Maps , también conocidos como matriz asociada, son un objeto que almacena los datos en forma de claves y valores. En Java, los mapas se representan mediante la interfaz de mapas, que no es una extensión de la interfaz de colección.

  • Camino 1: -

     /*J2SE < 5.0*/
     Map map = new HashMap();
     map.put("name", "A");
     map.put("address", "Malviya-Nagar");
     map.put("city", "Jaipur");
     System.out.println(map);
    
  • Camino 2: -

     /*J2SE 5.0+ style (use of generics):*/
     Map<String, Object> map = new HashMap<>();
     map.put("name", "A");
     map.put("address", "Malviya-Nagar");
     map.put("city", "Jaipur");
     System.out.println(map);
    
  • Camino 3: -

      Map<String, Object> map = new HashMap<String, Object>(){{
          put("name", "A");
          put("address", "Malviya-Nagar");
          put("city", "Jaipur");
      }};
      System.out.println(map);
    
  • Camino 4: -

      Map<String, Object> map = new TreeMap<String, Object>();
          map.put("name", "A");
          map.put("address", "Malviya-Nagar");
          map.put("city", "Jaipur");
      System.out.println(map);
    
  • Camino 5: -

      //Java 8
      final Map<String, String> map =
          Arrays.stream(new String[][] {
              { "name", "A" }, 
              { "address", "Malviya-Nagar" }, 
              { "city", "jaipur" },
          }).collect(Collectors.toMap(m -> m[0], m -> m[1]));
      System.out.println(map);
    
  • Camino 6: -

      //This way for initial a map in outside the function
      final static Map<String, String> map;
      static
      {
          map = new HashMap<String, String>();
          map.put("a", "b");
          map.put("c", "d");
      }
    
  • Forma 7: - Creando un único mapa de valor-clave inmutable.

        //Immutable single key-value map
        Map<String, String> singletonMap = Collections.singletonMap("key", "value");
    

    Tenga en cuenta que es imposible modificar dicho mapa .

    Cualquier intento de modificar el mapa resultará en lanzar la excepción UnsupportedOperationException.

        //Immutable single key-value pair
        Map<String, String> singletonMap = Collections.singletonMap("key", "value");
        singletonMap.put("newKey", "newValue"); //will throw UnsupportedOperationException
        singletonMap.putAll(new HashMap<>()); //will throw UnsupportedOperationException
        singletonMap.remove("key"); //will throw UnsupportedOperationException
        singletonMap.replace("key", "value", "newValue"); //will throw UnsupportedOperationException
        //and etc
    


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow