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.

Odpowiedzi:


258

Możesz to zrobić:

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

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?


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.


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]

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


Ś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}


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.


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


-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;
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.