aggiungendo più voci a una HashMap contemporaneamente in una sola istruzione


138

Devo inizializzare una HashMap costante e vorrei farlo in una riga. Evitando sth in questo modo:

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

simile a questo nell'obiettivo C:

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

Non ho trovato alcun esempio che mostri come farlo dopo averne visto così tanti.

Risposte:


259

Puoi farlo:

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

11
@ user387184 Sì, lo chiamano "inizializzatore a doppia parentesi graffa". Vedere questo argomento: stackoverflow.com/questions/924285/...
Eng.Fouad

2
L'ho appena inserito nel mio codice e ricevo questo avviso / messaggio nella riga: "La classe serializzabile non dichiara un campo serialVersionUID finale statico di tipo lungo". Posso ignorarlo? Cosa significa questo? Grazie
user387184

31
Non dovresti usare questo metodo. Crea una nuova classe per ogni volta che la usi, con prestazioni molto peggiori rispetto alla semplice creazione di una mappa. Vedere stackoverflow.com/questions/924285/...
Timo Türschmann

7
Il motivo per cui ho annullato il voto è perché non ha spiegato che questo crea una nuova classe per ogni volta che la usi. Penso che le persone dovrebbero essere consapevoli dei compromessi di farlo in questo modo.
idungotnosn,

6
@ TimoTürschmann Sembra che se avessi mai avuto bisogno di inizializzazione statica di una mappa come questa, sarebbe anche statica, eliminando ogni volta che la usi penalità di prestazione - avresti una volta quella penalità. Non vedo altre volte che si vorrebbe questo tipo di inizializzazione senza che la variabile fosse statica (ad esempio, qualcuno lo userebbe mai in un ciclo?). Potrei sbagliarmi, però, i programmatori sono inventivi.
Chris Cirefice,

65

Puoi utilizzare ImmutableMap di Google Guava. Funziona finché non ti interessa modificare la mappa in un secondo momento (non puoi chiamare .put () sulla mappa dopo averla costruita usando questo metodo):

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

Vedi anche: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html

Una domanda in qualche modo correlata: Soluzione alternativa a ImmutableMap.of () per HashMap in Maps?


Guava è enorme, non lo
userei

4
Attenzione che ImmutableMapnon accetta nullchiavi o valori.
Vadzim,

@ericn ProGuard ti consente di escludere qualsiasi parte di una libreria che non stai utilizzando.
dimo414,

55

Da Java 9, è possibile utilizzare Map.of(...), in questo modo:

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

Questa mappa è immutabile. Se vuoi che la mappa sia mutabile, devi aggiungere:

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

Se non riesci a utilizzare Java 9, sei bloccato con la scrittura di un metodo di supporto simile o con una libreria di terze parti (come Guava ) per aggiungere quella funzionalità per te.


Dopo aver aggiunto 10 voci, genera uno strano errore "impossibile risolvere il metodo", questo errore ha questo metodo?
vikramvi,

2
@vikramvi sì Se guardi la documentazione Map.of è fatta solo fino a 10 voci poiché è abbastanza laboriosa
jolivier

8

Java non ha una mappa letterale, quindi non c'è un bel modo di fare esattamente quello che stai chiedendo.

Se hai bisogno di quel tipo di sintassi, prendi in considerazione Groovy, che è compatibile con Java e ti consente di fare:

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

8

Le mappe hanno anche aggiunto metodi di fabbrica in Java 9. Per un massimo di 10 voci Le mappe hanno costruttori sovraccaricati che accettano coppie di chiavi e valori. Ad esempio, potremmo costruire una mappa delle varie città e delle loro popolazioni (secondo Google nell'ottobre 2016) come segue:

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

Il caso var-args per Map è un po 'più difficile, devi avere sia chiavi che valori, ma in Java i metodi non possono avere due parametri var-args. Quindi il caso generale viene gestito prendendo un metodo var-args di Map.Entry<K, V>oggetti e aggiungendo un entry()metodo statico che li costruisce. Per esempio:

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

Metodi di factory di raccolta in Java 9


Eccellente se si potesse usare Java 9+. Anche questo metodo di fabbrica restituisce una mappa immutabile.
Sourabh,

6

Ecco una semplice classe che realizzerà ciò che desideri

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

E poi usarlo

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

Questo cede {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 dichiarazione di x(che è necessaria per evitare una diagnosi di "dichiarazione irraggiungibile"), tecnicamente è solo una frase.


14
Questo è disgustosamente confuso.
Micah Stairs,

1
@MicahStairs - Ma è solo una frase.
Hot Licks

2
È vero, ma questo è il tipo di codice che non spero mai di imbattermi in produzione.
Micah Stairs,

@MicahStairs - Ho visto di peggio.
Hot Licks

1
Oh mio Dio, ho cercato questo oggi, come funziona questo codice? L'ho aggiunto nel codice per il test ma non riesco a capire come funziona internamente ... :)
GOXR3PLUS

1

È possibile aggiungere questa funzione di utilità a una classe di utilità:

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: in Java 9puoi usare Map.of


-1

Un altro approccio potrebbe essere la scrittura di una funzione speciale per estrarre tutti i valori degli elementi da una stringa mediante un'espressione regolare:

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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.