Agregar múltiples entradas a un HashMap a la vez en una declaración


138

Necesito inicializar un HashMap constante y me gustaría hacerlo en una declaración de línea. Evitando algo como esto:

  hashMap.put("One", new Integer(1)); // adding value into HashMap
  hashMap.put("Two", new Integer(2));      
  hashMap.put("Three", new Integer(3));

similar a esto en el objetivo C:

[NSDictionary dictionaryWithObjectsAndKeys:
@"w",[NSNumber numberWithInt:1],
@"K",[NSNumber numberWithInt:2],
@"e",[NSNumber numberWithInt:4],
@"z",[NSNumber numberWithInt:5],
@"l",[NSNumber numberWithInt:6],
nil] 

No he encontrado ningún ejemplo que muestre cómo hacer esto después de haber visto tantos.

Respuestas:


258

Puedes hacerlo:

Map<String, Integer> hashMap = new HashMap<String, Integer>()
{{
     put("One", 1);
     put("Two", 2);
     put("Three", 3);
}};

11
@ user387184 Sí, lo llaman "inicializador de doble paréntesis". Vea este tema: stackoverflow.com/questions/924285/…
Eng.Fouad

2
Acabo de ponerlo en mi código y aparece esta advertencia / mensaje en la línea: "La clase serializable no declara un campo estático final serialVersionUID de tipo largo". ¿Puedo ignorar eso? ¿Qué significa esto? Gracias
user387184

31
No deberías usar este método. Crea una nueva clase para cada vez que la usa, lo que tiene un rendimiento mucho peor que simplemente crear un mapa. Ver stackoverflow.com/questions/924285/…
Timo Türschmann

77
La razón por la que rechacé esto es porque no explica que esto crea una nueva clase por cada vez que la usas. Creo que la gente debería ser consciente de las ventajas y desventajas de hacerlo de esta manera.
idungotnosn

66
@ TimoTürschmann Parece que si alguna vez necesito la inicialización estática de un mapa como este, también sería estático, eliminando la penalización de rendimiento cada vez que lo use : tendría esa penalización una vez. No puedo ver en otro momento que uno quisiera este tipo de inicialización sin que la variable sea estática (por ejemplo, ¿alguien usaría esto en un bucle?). Sin embargo, puedo estar equivocado, los programadores son inventivos.
Chris Cirefice

65

Puede usar ImmutableMap de Google Guava. Esto funciona siempre que no te importe modificar el Mapa más tarde (no puedes llamar a .put () en el mapa después de construirlo usando este método):

import com.google.common.collect.ImmutableMap;

// For up to five entries, use .of()
Map<String, Integer> littleMap = ImmutableMap.of(
    "One", Integer.valueOf(1),
    "Two", Integer.valueOf(2),
    "Three", Integer.valueOf(3)
);

// For more than five entries, use .builder()
Map<String, Integer> bigMap = ImmutableMap.<String, Integer>builder()
    .put("One", Integer.valueOf(1))
    .put("Two", Integer.valueOf(2))
    .put("Three", Integer.valueOf(3))
    .put("Four", Integer.valueOf(4))
    .put("Five", Integer.valueOf(5))
    .put("Six", Integer.valueOf(6))
    .build();

Ver también: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html

Una pregunta algo relacionada: ¿ Solución alternativa de ImmutableMap.of () para HashMap en Maps?


La guayaba es enorme, yo no lo uso para mi aplicación Android a menos que sea absolutamente necesario
ericn

44
Cuidado que ImmutableMapno acepta nullclaves o valores.
Vadzim

@ericn ProGuard le permite excluir cualquier parte de una biblioteca que no esté utilizando.
dimo414

55

Desde Java 9, es posible usar Map.of(...), así:

Map<String, Integer> immutableMap = Map.of("One", 1, 
                                           "Two", 2, 
                                           "Three", 3);

Este mapa es inmutable. Si desea que el mapa sea mutable, debe agregar:

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

Si no puede usar Java 9, tiene que escribir un método auxiliar similar usted mismo o usar una biblioteca de terceros (como Guava ) para agregar esa funcionalidad por usted.


Después de agregar 10 entradas, arroja un extraño error "no se puede resolver el método".
vikramvi

2
@vikramvi sí Si miras la documentación Map.of solo se realizan hasta 10 entradas ya que es bastante laborioso
jolivier

8

Java no tiene un mapa literal, por lo que no hay una buena manera de hacer exactamente lo que está pidiendo.

Si necesita ese tipo de sintaxis, considere algunos Groovy, que es compatible con Java y le permite hacer:

def map = [name:"Gromit", likes:"cheese", id:1234]

8

Los mapas también han agregado métodos de fábrica en Java 9. Para hasta 10 entradas, los mapas han sobrecargado a los constructores que toman pares de claves y valores. Por ejemplo, podríamos construir un mapa de varias ciudades y sus poblaciones (según Google en octubre de 2016) de la siguiente manera:

Map<String, Integer> cities = Map.of("Brussels", 1_139000, "Cardiff", 341_000);

El caso de var-args para Map es un poco más difícil, necesita tener claves y valores, pero en Java, los métodos no pueden tener dos parámetros var-args. Entonces, el caso general se maneja tomando un método var-args de Map.Entry<K, V>objetos y agregando un entry()método estático que los construya. Por ejemplo:

Map<String, Integer> cities = Map.ofEntries(
    entry("Brussels", 1139000), 
    entry("Cardiff", 341000)
);

Métodos de Factory Factory en Java 9


Excelente si pudieras usar Java 9+. Además, este método de fábrica devuelve un mapa inmutable.
Sourabh

6

Aquí hay una clase simple que logrará lo que quieres

import java.util.HashMap;

public class QuickHash extends HashMap<String,String> {
    public QuickHash(String...KeyValuePairs) {
        super(KeyValuePairs.length/2);
        for(int i=0;i<KeyValuePairs.length;i+=2)
            put(KeyValuePairs[i], KeyValuePairs[i+1]);
    }
}

Y luego usarlo

Map<String, String> Foo=QuickHash(
    "a", "1",
    "b", "2"
);

Esto produce {a:1, b:2}


4
    boolean x;
    for (x = false, 
        map.put("One", new Integer(1)), 
        map.put("Two", new Integer(2)),      
        map.put("Three", new Integer(3)); x;);

Ignorando la declaración de x(que es necesaria para evitar un diagnóstico de "declaración inalcanzable"), técnicamente es solo una declaración.


14
Esto es asquerosamente hacky.
Micah Stairs

1
@MicahStairs - Pero es solo una declaración.
Hot Licks

2
Es cierto, pero este es el tipo de código que nunca espero encontrar en la producción.
Micah Stairs

@MicahStairs - He visto cosas peores.
Hot Licks

1
Omg, he buscado esto hoy, ¿cómo funciona este código? Lo he agregado al código para probarlo, pero no puedo entender cómo funciona internamente ... :)
GOXR3PLUS

1

Puede agregar esta función de utilidad a una clase de utilidad:

public static <K, V> Map<K, V> mapOf(Object... keyValues) {
    Map<K, V> map = new HashMap<>();

    for (int index = 0; index < keyValues.length / 2; index++) {
        map.put((K)keyValues[index * 2], (V)keyValues[index * 2 + 1]);
    }

    return map;
}

Map<Integer, String> map1 = YourClass.mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = YourClass.mapOf("key1", "value1", "key2", "value2");

Nota: en Java 9puedes usar Map.of


-1

Otro enfoque puede ser escribir una función especial para extraer todos los valores de los elementos de una cadena por expresión regular:

import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Example {
    public static void main (String[] args){
        HashMap<String,Integer> hashMapStringInteger = createHashMapStringIntegerInOneStat("'one' => '1', 'two' => '2' , 'three'=>'3'  ");

        System.out.println(hashMapStringInteger); // {one=1, two=2, three=3}
    }

    private static HashMap<String, Integer> createHashMapStringIntegerInOneStat(String str) {
        HashMap<String, Integer> returnVar = new HashMap<String, Integer>();

        String currentStr = str;
        Pattern pattern1 = Pattern.compile("^\\s*'([^']*)'\\s*=\\s*>\\s*'([^']*)'\\s*,?\\s*(.*)$");

        // Parse all elements in the given string.
        boolean thereIsMore = true;
        while (thereIsMore){
            Matcher matcher = pattern1.matcher(currentStr);
            if (matcher.find()) {
                returnVar.put(matcher.group(1),Integer.valueOf(matcher.group(2)));
                currentStr = matcher.group(3);
            }
            else{
                thereIsMore = false;
            }
        }

        // Validate that all elements in the given string were parsed properly
        if (currentStr.length() > 0){
            System.out.println("WARNING: Problematic string format. given String: " + str);
        }

        return returnVar;
    }
}
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.