dodawanie wielu wpisów do HashMap jednocześnie w jednej instrukcji

138

Muszę zainicjować stałą HashMap i chciałbym to zrobić w jednym wierszu instrukcji. Unikanie czegoś takiego:

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

podobnie jak w celu C:

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

Nie znalazłem żadnego przykładu, który pokazuje, jak to zrobić, patrząc na tak wielu.

user387184
źródło

Odpowiedzi:

258

Możesz to zrobić:

Map<String, Integer> hashMap = new HashMap<String, Integer>()
{{
     put("One", 1);
     put("Two", 2);
     put("Three", 3);
}};
Eng.Fouad
źródło
11
@ user387184 Tak, nazywają to „inicjatorem podwójnych nawiasów klamrowych”. Zobacz ten temat: stackoverflow.com/questions/924285/ ...
Eng.Fouad
2
Po prostu umieściłem go w swoim kodzie i otrzymałem ostrzeżenie / komunikat w wierszu: „Klasa możliwa do serializacji nie deklaruje statycznego końcowego pola serialVersionUID typu long”. Mogę to po prostu zignorować? co to znaczy? Dzięki
user387184
31
Nie powinieneś używać tej metody. Tworzy nową klasę za każdym razem, gdy jej używasz, co ma znacznie gorszą wydajność niż zwykłe tworzenie mapy. Zobacz stackoverflow.com/questions/924285/…
Timo Türschmann
7
Powodem, dla którego to odrzuciłem, jest to, że nie wyjaśniało, że tworzy to nową klasę za każdym razem, gdy jej używasz. Myślę, że ludzie powinni być świadomi kompromisów związanych z robieniem tego w ten sposób.
idungotnosn
6
@ TimoTürschmann Wydaje się, że gdybym kiedykolwiek potrzebował statycznej inicjalizacji mapy takiej jak ta, to byłaby również statyczna, eliminując spadek wydajności za każdym razem, gdy jej użyjesz - miałbyś tę karę raz. Nie widzę innego razu, aby ktoś chciał tego rodzaju inicjalizacji bez statycznej zmiennej (np. Czy ktoś kiedykolwiek użyłby tego w pętli?). Chociaż mogę się mylić, programiści są pomysłowi.
Chris Cirefice
65

Możesz użyć ImmutableMap Google Guava. Działa to o ile nie zależy ci na późniejszej modyfikacji mapy (nie możesz wywołać .put () na mapie po skonstruowaniu jej przy użyciu tej metody):

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

Zobacz też: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html

Dość powiązane pytanie: obejście ImmutableMap.of () dla HashMap w Mapach?

JimmyT
źródło
Guawa jest ogromna, nie
użyłbym
4
Uważaj, ImmutableMapjeśli nie akceptujesz nullkluczy ani wartości.
Wadzim
@ericn ProGuard pozwala wykluczyć dowolne części biblioteki, których nie używasz.
dimo414
55

Od wersji Java 9 można używać Map.of(...), na przykład:

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

Ta mapa jest niezmienna. Jeśli chcesz, aby mapa była zmienna, musisz dodać:

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

Jeśli nie możesz użyć Javy 9, utkniesz w pisaniu podobnej metody pomocniczej samodzielnie lub korzystaniu z biblioteki innej firmy (takiej jak Guava ), aby dodać tę funkcjonalność za Ciebie.

Timo Türschmann
źródło
Po dodaniu 10 wpisów wyrzuca dziwny błąd „nie można rozwiązać metody”, czy to błąd w tej metodzie?
vikramvi
2
@vikramvi tak Jeśli spojrzysz na dokumentację, Map.of zrobisz tylko do 10 wpisów, ponieważ jest to dość pracochłonne
jolivier
8

Java nie ma literału mapy, więc nie ma dobrego sposobu na zrobienie dokładnie tego, o co prosisz.

Jeśli potrzebujesz tego typu składni, rozważ Groovy, który jest kompatybilny z Javą i pozwala ci:

def map = [name:"Gromit", likes:"cheese", id:1234]
dfraser
źródło
8

Mapy mają również dodane metody fabryczne w Javie 9. Dla maksymalnie 10 wpisów Mapy mają przeciążone konstruktory, które pobierają pary kluczy i wartości. Na przykład moglibyśmy zbudować mapę różnych miast i ich populacji (według Google w październiku 2016) w następujący sposób:

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

Przypadek var-args dla Map jest nieco trudniejszy, musisz mieć zarówno klucze, jak i wartości, ale w Javie metody nie mogą mieć dwóch parametrów var-args. Tak więc ogólny przypadek jest obsługiwany przez przyjęcie metody var-args Map.Entry<K, V>obiektów i dodanie statycznej entry()metody, która je konstruuje. Na przykład:

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

Collection Factory Methods w Javie 9

Sadiq Ali
źródło
Świetnie, gdybyś mógł używać Java 9+. Również ta metoda fabryczna zwraca niezmienną mapę.
Sourabh
6

Oto prosta klasa, która spełni Twoje oczekiwania

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

A potem go użyć

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

To daje {a:1, b:2}

Dakusan
źródło
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;);

Ignorując deklarację x(która jest niezbędna, aby uniknąć diagnostyki „nieosiągalnej instrukcji”), technicznie jest to tylko jedna instrukcja.

Hot Licks
źródło
14
To jest obrzydliwie hacky.
Schody Micah
1
@MicahStairs - Ale to tylko jedno stwierdzenie.
Hot Licks
2
To prawda, ale jest to rodzaj kodu, na który nigdy nie mam nadziei natknąć się podczas produkcji.
Schody Micah
@MicahStairs - widziałem gorsze.
Hot Licks
1
Omg Szukałem tego dzisiaj, jak działa ten kod? Dodałem go do kodu do testów, ale nie wiem, jak to działa wewnętrznie ... :)
GOXR3PLUS
1

Możesz dodać tę funkcję narzędziową do klasy narzędziowej:

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

Uwaga: w Java 9możesz użyć Map.of

R. Oosterholt
źródło
-1

Innym podejściem może być napisanie specjalnej funkcji, która wyodrębni wszystkie wartości elementów z jednego ciągu za pomocą wyrażenia regularnego:

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
źródło