ajouter plusieurs entrées à un HashMap à la fois dans une seule instruction

138

J'ai besoin d'initialiser un HashMap constant et j'aimerais le faire en une seule ligne. Éviter qc comme ça:

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

similaire à celui de l'objectif C:

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

Je n'ai trouvé aucun exemple qui montre comment faire cela après en avoir examiné autant.

user387184
la source

Réponses:

259

Tu peux le faire:

Map<String, Integer> hashMap = new HashMap<String, Integer>()
{{
     put("One", 1);
     put("Two", 2);
     put("Three", 3);
}};
Ing. Fouad
la source
11
@ user387184 Ouais, ils l'appellent "initialiseur double accolade". Voir ce sujet: stackoverflow.com/questions/924285/…
Eng.Fouad
2
Je viens de le mettre dans mon code et j'obtiens cet avertissement / message dans la ligne: "La classe sérialisable ne déclare pas un champ serialVersionUID final statique de type long". Puis-je simplement ignorer cela? Qu'est-ce que ça veut dire? Merci
user387184
31
Vous ne devez pas utiliser cette méthode. Il crée une nouvelle classe à chaque fois que vous l'utilisez, ce qui a des performances bien pires que la simple création d'une carte. Voir stackoverflow.com/questions/924285/…
Timo Türschmann
7
La raison pour laquelle j'ai refusé cela est parce que cela n'expliquait pas que cela crée une nouvelle classe à chaque fois que vous l'utilisez. Je pense que les gens devraient être conscients des compromis à faire de cette façon.
idungotnosn
6
@ TimoTürschmann Il semble que si jamais j'avais besoin d'une initialisation statique d'une carte comme celle-ci, elle serait également statique, éliminant chaque fois que vous l'utiliserez une pénalité de performance - vous auriez cette pénalité une fois. Je ne vois aucun autre moment où l'on voudrait ce genre d'initialisation sans que la variable soit statique (par exemple, est-ce que quelqu'un l'utiliserait jamais dans une boucle?). Je me trompe peut-être, les programmeurs sont inventifs.
Chris Cirefice
65

Vous pouvez utiliser ImmutableMap de Google Guava. Cela fonctionne tant que vous ne vous souciez pas de modifier la carte plus tard (vous ne pouvez pas appeler .put () sur la carte après l'avoir construite à l'aide de cette méthode):

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();

Voir également: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html

Une question quelque peu liée: Solution de contournement ImmutableMap.of () pour HashMap dans Maps?

JimmyT
la source
La goyave est énorme, je ne l'utiliserais pas pour mon application Android à moins que cela ne soit absolument nécessaire
ericn
4
Méfiez-vous qui ImmutableMapn'accepte pas les nullclés ou les valeurs.
Vadzim
@ericn ProGuard vous permet d'exclure toutes les parties d'une bibliothèque que vous n'utilisez pas.
dimo414
55

Depuis Java 9, il est possible d'utiliser Map.of(...), comme ceci:

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

Cette carte est immuable. Si vous souhaitez que la carte soit modifiable, vous devez ajouter:

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

Si vous ne pouvez pas utiliser Java 9, vous êtes obligé d'écrire vous-même une méthode d'aide similaire ou d'utiliser une bibliothèque tierce (comme Guava ) pour ajouter cette fonctionnalité pour vous.

Timo Türschmann
la source
Après avoir ajouté 10 entrées, il jette une erreur étrange "ne peut pas résoudre la méthode", est ce bogue avec cette méthode?
vikramvi le
2
@vikramvi oui Si vous regardez la documentation Map.of on ne fait que jusqu'à 10 entrées car c'est assez laborieux
jolivier
8

Java n'a pas de littéral de carte, il n'y a donc pas de moyen agréable de faire exactement ce que vous demandez.

Si vous avez besoin de ce type de syntaxe, pensez à Groovy, qui est compatible Java et vous permet de faire:

def map = [name:"Gromit", likes:"cheese", id:1234]
dfraser
la source
8

Les cartes ont également eu des méthodes d'usine ajoutées dans Java 9. Pour jusqu'à 10 entrées, les cartes ont surchargé les constructeurs qui prennent des paires de clés et de valeurs. Par exemple, nous pourrions construire une carte de différentes villes et de leurs populations (selon google en octobre 2016) comme suit:

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

Le cas var-args pour Map est un peu plus difficile, vous devez avoir à la fois des clés et des valeurs, mais en Java, les méthodes ne peuvent pas avoir deux paramètres var-args. Le cas général est donc géré en prenant une méthode d' Map.Entry<K, V>objets var-args et en ajoutant une entry()méthode statique qui les construit. Par exemple:

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

Méthodes d'usine de collecte dans Java 9

Sadiq Ali
la source
Excellent si vous pouviez utiliser Java 9+. De plus, cette méthode de fabrique renvoie une carte immuable.
Sourabh
6

Voici un cours simple qui accomplira ce que vous voulez

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]);
    }
}

Et puis de l'utiliser

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

Cela donne {a:1, b:2}

Dakusan
la source
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;);

Ignorant la déclaration de x(qui est nécessaire pour éviter un diagnostic "instruction inaccessible"), techniquement, ce n'est qu'une instruction.

Hot Licks
la source
14
C'est terriblement piraté.
Micah Stairs
1
@MicahStairs - Mais ce n'est qu'une seule déclaration.
Hot Licks
2
C'est vrai, mais c'est le genre de code sur lequel je n'espère jamais tomber en production.
Micah Stairs
@MicahStairs - J'ai vu pire.
Hot Licks
1
Omg j'ai recherché ceci aujourd'hui, comment ce code fonctionne? Je l'ai ajouté dans le code pour le test mais je ne peux pas comprendre comment cela fonctionne en interne ... :)
GOXR3PLUS
1

Vous pouvez ajouter cette fonction utilitaire à une classe utilitaire:

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");

Remarque: dans Java 9vous pouvez utiliser Map.of

R. Oosterholt
la source
-1

Une autre approche peut consister à écrire une fonction spéciale pour extraire toutes les valeurs d'éléments d'une chaîne par expression régulière:

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;
    }
}
Uri Ziv
la source