web-dev-qa-db-fra.com

Comment initialiser directement un HashMap (de manière littérale)?

Existe-t-il un moyen d'initialiser un Java HashMap comme celui-ci ?:

Map<String,String> test = 
    new HashMap<String, String>{"test":"test","test":"test"};

Quelle serait la syntaxe correcte? Je n'ai rien trouvé à ce sujet. Est-ce possible? Je recherche le moyen le plus rapide/le plus rapide de définir des valeurs "finales/statiques" dans une carte, qui ne changent jamais et sont connues à l’avance lors de la création de la carte.

937
jens

Pour Java Version 9 ou supérieure:

Oui, c'est possible maintenant. Dans Java 9, deux méthodes d'usine ont été ajoutées pour simplifier la création de cartes:

// this works for up to 10 elements:
Map<String, String> test1 = Map.of(
    "a", "b",
    "c", "d"
);

// this works for any number of elements:
Map<String, String> test2 = Map.ofEntries(
    entry("a", "b"),
    entry("c", "d")
);

Dans l'exemple ci-dessus, test et test2 seront identiques, mais avec différentes manières d'exprimer la carte. La méthode Map.of est définie pour un maximum de dix éléments de la carte, tandis que la méthode Map.ofEntries n'a pas cette limite.

Notez que dans ce cas, la carte résultante sera une carte immuable. Si vous souhaitez que la carte soit modifiable, vous pouvez la copier à nouveau, par exemple. en utilisant mutableMap = new HashMap<>(Map.of("a", "b"));

(Voir aussi JEP 269 et le Javadoc )

Jusqu'à Java version 8:

Non, vous devrez ajouter tous les éléments manuellement. Vous pouvez utiliser un initialiseur dans une sous-classe anonyme pour raccourcir un peu la syntaxe:

Map<String, String> myMap = new HashMap<>() {{
        put("a", "b");
        put("c", "d");
    }};

Cependant, la sous-classe anonyme peut introduire un comportement indésirable dans certains cas. Cela comprend par exemple:

  • Il génère une classe supplémentaire qui augmente la consommation de mémoire, la consommation d'espace disque et le temps de démarrage.
  • Dans le cas d'une méthode non statique: Il contient une référence à l'objet sur lequel la méthode de création a été appelée. Cela signifie que l'objet de la classe externe ne peut pas être nettoyé alors que l'objet de carte créé est toujours référencé, bloquant ainsi de la mémoire supplémentaire.

L'utilisation d'une fonction d'initialisation vous permettra également de générer une carte dans un initialiseur, tout en évitant les effets secondaires désagréables:

Map<String, String> myMap = createMap();

private static Map<String, String> createMap() {
    Map<String,String> myMap = new HashMap<String,String>();
    myMap.put("a", "b");
    myMap.put("c", "d");
    return myMap;
}
1136
yankee

C'est une façon.

HashMap<String, String> h = new HashMap<String, String>() {{
    put("a","b");
}};

Toutefois, vous devez faire attention et comprendre le code ci-dessus (il crée une nouvelle classe qui hérite de HashMap). Par conséquent, vous devriez lire plus ici: http://www.c2.com/cgi/wiki?DoubleBraceInitialization , ou simplement utiliser Guava:

Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
1010
gregory561

Si vous autorisez des bibliothèques tierces, vous pouvez utiliser les commandes de ImmutableMap de Guava pour obtenir une concision de type littéral:

Map<String, String> test = ImmutableMap.of("k1", "v1", "k2", "v2");

Cela fonctionne jusqu'à 5 paires clé/valeur , sinon vous pouvez utiliser son constructeur :

Map<String, String> test = ImmutableMap.<String, String>builder()
    .put("k1", "v1")
    .put("k2", "v2")
    ...
    .build();


  • notez que l'implémentation ImmutableMap de Guava diffère de l'implémentation HashMap de Java (notamment, elle est immuable et n'autorise pas les clés/valeurs nulles)
  • pour plus d'informations, voir l'article du guide de l'utilisateur de Guava sur ses types de collection immuables
327
Jens Hoffmann

Il n'y a pas de moyen direct de le faire - Java n'a pas de littéraux de carte (pour l'instant, je pense qu'ils ont été proposés pour Java 8).

Certaines personnes aiment ça:

Map<String,String> test = new HashMap<String, String>(){{
       put("test","test"); put("test","test");}};

Cela crée une sous-classe anonyme de HashMap, dont l'initialiseur d'instance met ces valeurs. (Au fait, une carte ne peut pas contenir deux fois la même valeur, votre deuxième vente écrasera la première. J'utiliserai des valeurs différentes pour les exemples suivants.)

La manière normale serait la suivante (pour une variable locale):

Map<String,String> test = new HashMap<String, String>();
test.put("test","test");
test.put("test1","test2");

Si votre carte test est une variable d'instance, placez l'initialisation dans un constructeur ou un initialiseur d'instance:

Map<String,String> test = new HashMap<String, String>();
{
    test.put("test","test");
    test.put("test1","test2");
}

Si votre carte test est une variable de classe, placez l'initialisation dans un initialiseur statique:

static Map<String,String> test = new HashMap<String, String>();
static {
    test.put("test","test");
    test.put("test1","test2");
}

Si vous souhaitez que votre carte ne change jamais, vous devriez, après l'initialisation, envelopper votre carte par Collections.unmodifiableMap(...). Vous pouvez également le faire dans un initialiseur statique:

static Map<String,String> test;
{
    Map<String,String> temp = new HashMap<String, String>();
    temp.put("test","test");
    temp.put("test1","test2");
    test = Collections.unmodifiableMap(temp);
}

(Je ne sais pas si vous pouvez maintenant faire test final ... essayez-le et faites un rapport ici.)

103
Paŭlo Ebermann
Map<String,String> test = new HashMap<String, String>()
{
    {
        put(key1, value1);
        put(key2, value2);
    }
};
61
Shaggy Frog

Une alternative utilisant plain Java 7 classes et variables: crée une classe HashMapBuilder avec cette méthode:

public static HashMap<String, String> build(String... data){
    HashMap<String, String> result = new HashMap<String, String>();

    if(data.length % 2 != 0) 
        throw new IllegalArgumentException("Odd number of arguments");      

    String key = null;
    Integer step = -1;

    for(String value : data){
        step++;
        switch(step % 2){
        case 0: 
            if(value == null)
                throw new IllegalArgumentException("Null key value"); 
            key = value;
            continue;
        case 1:             
            result.put(key, value);
            break;
        }
    }

    return result;
}

Utilisez la méthode comme ceci:

HashMap<String,String> data = HashMapBuilder.build("key1","value1","key2","value2");
42
Aerthel