Jak bezpośrednio zainicjować Hashmapę (w dosłowny sposób)?

Czy Jest jakiś sposób na zainicjowanie takiej Hashmapy w Javie?:

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

Jaka byłaby prawidłowa składnia? Nie znalazłem nic na ten temat. Czy to możliwe? Szukam najkrótszego/najszybszego sposobu, aby umieścić pewne "końcowe / statyczne" wartości na mapie, które nigdy się nie zmieniają i są znane z góry podczas tworzenia mapy.

Author: Freedom_Ben, 2011-07-23

16 answers

Wszystkie Wersje

Jeśli zdarzy ci się potrzebować tylko jednego wpisu: jest Collections.singletonMap("key", "value").

Dla Javy w wersji 9 lub wyższej:

Tak, Teraz jest to możliwe. W Javie 9 dodano kilka fabrycznych metod, które upraszczają tworzenie map:
// this works for up to 10 elements:
Map<String, String> test1 = Map.of(
    "a", "b",
    "c", "d"
);

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

W powyższym przykładzie zarówno test jak i test2 będą takie same, tylko z różnymi sposobami wyrażania Mapy. Metoda Map.of jest zdefiniowana dla maksymalnie dziesięciu elementów na mapie, natomiast metoda Map.ofEntries nie będzie miała taki limit.

Zauważ, że w tym przypadku Mapa wynikowa będzie niezmienna. Jeśli chcesz, aby mapa była zmienna, możesz ją skopiować ponownie, np. używając mutableMap = new HashMap<>(Map.of("a", "b"));

(Zobacz także JEP 269 i Javadoc)

Do wersji Java 8:

Nie, musisz dodać wszystkie elementy ręcznie. Możesz użyć inicjalizatora w anonimowej podklasie, aby skrócić składnię:

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

Jednak anonimowa podklasa może wprowadzenie niechcianych zachowań w niektórych przypadkach. Obejmuje to na przykład:

  • generuje dodatkową klasę, która zwiększa zużycie pamięci, zużycie miejsca na dysku i czas uruchamiania
  • W przypadku metody niestatycznej: zawiera odniesienie do obiektu, do którego została wywołana metoda wytwarzania. Oznacza to, że obiekt klasy zewnętrznej nie może być pobierany podczas gdy utworzony obiekt mapy jest nadal odwoływany, blokując w ten sposób dodatkową pamięć

Za pomocą funkcja inicjalizacji umożliwi również wygenerowanie mapy w inicjalizatorze, ale unika nieprzyjemnych efektów ubocznych:

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;
}
 1570
Author: yankee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-21 18:45:42

To jest jeden sposób.

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

Jednak powinieneś być ostrożny i upewnić się, że rozumiesz powyższy kod(tworzy on nową klasę, która dziedziczy z HashMap). Dlatego warto przeczytać więcej tutaj: http://www.c2.com/cgi/wiki?DoubleBraceInitialization , lub po prostu użyć guawy:

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

ImmutableMap.of działa do 5 wpisów. W przeciwnym razie użyj konstruktora: source .

 1068
Author: gregory561,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-03 20:57:51

Jeśli zezwalasz na Biblioteki stron trzecich, możesz użyć Guava 'S ImmutableMap aby osiągnąć zwięzłość dosłowną:

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

To działa dla maksymalnie 5 par klucz/wartość , w przeciwnym razie możesz użyć jego builder :

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


    W przeciwieństwie do Javy, Java nie może być używana do tworzenia kopii zapasowych (np. kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych, kopii zapasowych itp.)]}
  • aby uzyskać więcej informacji, zobacz Guava ' s user guide article on its immutable collection types
 353
Author: Jens Hoffmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-06 07:23:04

Nie ma na to bezpośredniego sposobu-Java nie ma literałów Map (jeszcze-myślę, że zostały zaproponowane dla Javy 8).

Niektórzy ludzie lubią to:

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

Tworzy to anonimową podklasę HashMap, której inicjalizator instancji umieszcza te wartości. (Nawiasem mówiąc, mapa nie może zawierać dwukrotnie tej samej wartości, twoje drugie put nadpisze pierwszą. W następnych przykładach użyję różnych wartości.)

Normalnym sposobem byłoby to (dla lokalnego zmienna):

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

Jeśli Twoja mapa test jest zmienną instancji, umieść inicjalizację w konstruktorze lub inicjalizatorze instancji:

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

Jeśli Twoja mapa test jest zmienną klasy, umieść inicjalizację w statycznym inicjalizatorze:

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

Jeśli chcesz, aby Mapa nigdy się nie zmieniała, powinieneś po inicjalizacji zawinąć Mapę przez Collections.unmodifiableMap(...). Możesz to zrobić również w statycznym inicjalizatorze:

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

(nie jestem pewien, czy możesz teraz zrobić test finał ... wypróbuj i zgłoś proszę.)

 109
Author: Paŭlo Ebermann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-28 21:21:27
Map<String,String> test = new HashMap<String, String>()
{
    {
        put(key1, value1);
        put(key2, value2);
    }
};
 63
Author: Shaggy Frog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-23 18:47:06

Alternatywa, używając zwykłych klas Java 7 i varargs: Utwórz klasę HashMapBuilder za pomocą tej metody:

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

Użyj metody w ten sposób:

HashMap<String,String> data = HashMapBuilder.build("key1","value1","key2","value2");
 45
Author: Aerthel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-04 16:10:23

JAVA 8

W zwykłej Javie 8 masz również możliwość użycia Streams/Collectors do wykonania zadania.

Map<String, String> myMap = Stream.of(
         new SimpleEntry<>("key1", "value1"),
         new SimpleEntry<>("key2", "value2"),
         new SimpleEntry<>("key3", "value3"))
        .collect(toMap(SimpleEntry::getKey, SimpleEntry::getValue));

To ma tę zaletę, że nie tworzy anonimowej klasy.

Zauważ, że import to:

import static java.util.stream.Collectors.toMap;
import java.util.AbstractMap.SimpleEntry;

Oczywiście, jak zauważono w innych odpowiedziach, w Javie 9 Od początku masz prostsze sposoby robienia tego samego.

 7
Author: Johnny Willer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-30 20:54:12

Tl;dr

Użyj metod Map.of… w Javie 9 i nowszych.

Map< String , String > animalSounds =
    Map.of(
        "dog"  , "bark" ,   // key , value
        "cat"  , "meow" ,   // key , value
        "bird" , "chirp"    // key , value
    )
;

Map.of

Java 9 dodała serię Map.of statyczne metody do robienia tego, co chcesz: tworzy instancję niezmienną Map używając dosłownej składni.

Mapa (zbiór wpisów) jest niezmienna, więc nie można dodawać ani usuwać wpisów po utworzeniu instancji. Ponadto klucz i wartość każdego wpisu są niezmienne, nie można ich zmienić. Zobacz Javadoc dla innych zasad, takich ponieważ Null nie jest dozwolone, duplikaty kluczy nie są dozwolone, a kolejność odwzorowania iteracji jest dowolna.

Przyjrzyjmy się tym metodom, używając przykładowych danych do mapy dnia tygodnia dla osoby, której oczekujemy, że będzie pracować w tym dniu.

Person alice = new Person( "Alice" );
Person bob = new Person( "Bob" );
Person carol = new Person( "Carol" );

Map.of()

Map.of tworzy pusty Map. Niezmodyfikowane, więc nie można dodawać wpisów. Oto przykład takiej mapy, pustej bez wpisów.

Map < DayOfWeek, Person > dailyWorkerEmpty = Map.of();

DailyWorkerEmpty.toString(): {}

Map.of( … )

Map.of( k , v , k , v , …) jest kilka metod, które przyjmują od 1 do 10 par klucz-wartość. Oto przykład dwóch wpisów.

Map < DayOfWeek, Person > weekendWorker = 
        Map.of( 
            DayOfWeek.SATURDAY , alice ,     // key , value
            DayOfWeek.SUNDAY , bob           // key , value
        )
;

WeekendWorker.toString (): {niedziela=osoba{ imię= 'Bob'}, sobota=osoba{ imię = 'Alicja' }}

Map.ofEntries( … )

Map.ofEntries( Map.Entry , … ) zajmuje dowolną liczbę obiektów realizujących Map.Entry interfejs. Java łączy dwie klasy implementujące ten interfejs, jedną zmienną, drugą niezmienną: AbstractMap.SimpleEntry, AbstractMap.SimpleImmutableEntry. Ale nie musimy określać konkretnej klasy. Wystarczy zadzwonić Map.entry( k , v ) method, przekazujemy nasz klucz i naszą wartość, a otrzymujemy obiekt jakiejś klasy implementującej Map.Entry interfejs.

Map < DayOfWeek, Person > weekdayWorker = Map.ofEntries(
        Map.entry( DayOfWeek.MONDAY , alice ) ,            // Call to `Map.entry` method returns an object implementing `Map.Entry`. 
        Map.entry( DayOfWeek.TUESDAY , bob ) ,
        Map.entry( DayOfWeek.WEDNESDAY , bob ) ,
        Map.entry( DayOfWeek.THURSDAY , carol ) ,
        Map.entry( DayOfWeek.FRIDAY , carol )
);

WeekdayWorker.toString (): {środa=osoba{ imię = 'Bob'}, wtorek=osoba{ imię = 'Bob'}, czwartek=osoba{ imię = 'Carol'}, piątek= osoba{ imię = 'Carol'}, poniedziałek=osoba{ imię = 'Alicja' }}

Map.copyOf

Java 10 dodała metodę Map.copyOf. Przekazać istniejącą mapę, odzyskać niezmienną kopię tej mapy.

Uwagi

Zauważ, że kolejność iteratorów map produkowanych przez Map.of jest, a nie gwarantowana. Wpisy mają dowolną kolejność. Nie pisz kodu na podstawie widzianego zamówienia, ponieważ dokumentacja ostrzega, że zamówienie może ulec zmianie.

Zauważ, że wszystkie te Map.of… metody zwracają Map Z nieokreślona Klasa . Podstawowa klasa betonu może się nawet różnić w zależności od wersji Javy. Ta anonimowość pozwala Javie wybierać spośród różnych implementacji, niezależnie od tego, co optymalnie pasuje do konkretnych danych. Na przykład, jeśli klucze pochodzą z enum, Java może używać EnumMap pod kołdrą.

 5
Author: Basil Bourque,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-16 15:22:16

Możemy użyć klasy AbstractMap posiadającej SimpleEntry, która pozwala na tworzenie niezmiennej Mapy

Map<String, String> map5 = Stream.of(
    new AbstractMap.SimpleEntry<>("Sakshi","java"),
    new AbstractMap.SimpleEntry<>("fine","python")
    ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    
    System.out.println(map5.get("Sakshi"));
    map5.put("Shiva", "Javascript");
    System.out.println(map5.get("Shiva"));// here we can add multiple entries.
 2
Author: Sakshi Aggarwal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-17 18:13:18

Możesz łatwo stworzyć własną metodę Map.of (która jest dostępna tylko w Javie 9 i wyższych) na dwa proste sposoby

Make it with a set amount of parameters

Przykład

public <K,V> Map<K,V> mapOf(K k1, V v1, K k2, V v2 /* perhaps more parameters */) {
    return new HashMap<K, V>() {{
      put(k1, v1);
      put(k2,  v2);
      // etc...
    }};
}

Zrób to za pomocą listy

Można również zrobić to za pomocą listy, zamiast tworzenia wielu metod dla określonego zestawu parametrów.

Przykład

public <K, V> Map<K, V> mapOf(List<K> keys, List<V> values) {
   if(keys.size() != values.size()) {
        throw new IndexOutOfBoundsException("amount of keys and values is not equal");
    }

    return new HashMap<K, V>() {{
        IntStream.range(0, keys.size()).forEach(index -> put(keys.get(index), values.get(index)));
    }};
}

Uwaga Nie zaleca się używania tego do wszystkiego, ponieważ za każdym razem tworzy to anonimową klasę użyj tego.

 1
Author: NotNV6,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-23 12:00:49

Jeśli chcesz umieścić tylko jedną parę klucz-wartość, możesz użyć kolekcji.singletonMap (klucz, wartość);

 1
Author: Balakrishna Kudikala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-09 18:46:38

Z Java 8 lub mniej

Możesz użyć statycznego bloku, aby zainicjować mapę z pewnymi wartościami. Przykład:

public static Map<String,String> test = new HashMap<String, String>

static {
    test.put("test","test");
    test.put("test1","test");
}

Z Java 9 lub więcej

Możesz użyć mapy.of () metoda inicjalizacji mapy z pewnymi wartościami podczas deklarowania. Przykład:

public static Map<String,String> test = Map.of("test","test","test1","test");
 1
Author: Vishal Saraf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-21 06:16:36

Niestety, używanie varargs, jeśli Typ kluczy i wartości nie są takie same, nie jest zbyt rozsądne, ponieważ trzeba by użyć Object... i całkowicie stracić bezpieczeństwo typu. Jeśli zawsze chcesz utworzyć np. a Map<String, String>, oczywiście a toMap(String... args) byłoby możliwe, ale nie bardzo ładne, ponieważ łatwo byłoby pomieszać klucze i wartości, a Nieparzysta liczba argumentów byłaby nieprawidłowa.

Możesz utworzyć podklasę HashMap, która ma metodę łańcuchową, taką jak

public class ChainableMap<K, V> extends HashMap<K, V> {
  public ChainableMap<K, V> set(K k, V v) {
    put(k, v);
    return this;
  }
}

I używać go jak new ChainableMap<String, Object>().set("a", 1).set("b", "foo")

Innym podejściem jest użycie wspólnego wzorca konstruktora:

public class MapBuilder<K, V> {
  private Map<K, V> mMap = new HashMap<>();

  public MapBuilder<K, V> put(K k, V v) {
    mMap.put(k, v);
    return this;
  }

  public Map<K, V> build() {
    return mMap;
  }
}

I używać go jak new MapBuilder<String, Object>().put("a", 1).put("b", "foo").build();

Jednak rozwiązanie, którego używałem od czasu do czasu, wykorzystuje varargs i klasę Pair:

public class Maps {
  public static <K, V> Map<K, V> of(Pair<K, V>... pairs) {
    Map<K, V> = new HashMap<>();

    for (Pair<K, V> pair : pairs) {
      map.put(pair.first, pair.second);
    }

    return map;
  }
}

Map<String, Object> map = Maps.of(Pair.create("a", 1), Pair.create("b", "foo");

Słowność Pair.create() trochę mnie niepokoi, ale to działa całkiem dobrze. Jeśli nie masz nic przeciwko importom statycznym, możesz oczywiście utworzyć helper:

public <K, V> Pair<K, V> p(K k, V v) {
  return Pair.create(k, v);
}

Map<String, Object> map = Maps.of(p("a", 1), p("b", "foo");

(zamiast Pair można sobie wyobrazić użycie Map.Entry, ale ponieważ jest to interfejs wymaga klasy implementującej i / lub metody fabrycznej helpera. Nie jest również niezmienny i zawiera inną logikę, która nie jest przydatna do tego zadania.)

 0
Author: JHH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-17 09:53:24

Możesz używać strumieni w Javie 8 (jest to exmaple of Set):

@Test
public void whenInitializeUnmodifiableSetWithDoubleBrace_containsElements() {
    Set<String> countries = Stream.of("India", "USSR", "USA")
      .collect(collectingAndThen(toSet(), Collections::unmodifiableSet));

    assertTrue(countries.contains("India"));
}

Ref: https://www.baeldung.com/java-double-brace-initialization

 0
Author: Robocide,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-03 16:40:12

Możesz utworzyć metodę inicjalizacji mapy jak w poniższym przykładzie:

Map<String, Integer> initializeMap()
{
  Map<String, Integer> ret = new HashMap<>();

  //populate ret
  ...

  return ret;
}

//call
Map<String, Integer> map = initializeMap();
 0
Author: Alan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-17 08:23:40

Możemy zainicjalizować hashmap używając następujących sposobów:

  1. HashMap using Constructor

    Map hashMap = new HashMap();

     hashMap.put("hcl", "amit");
    
     hashMap.put("tcs","ravi");
    

Hashmap ma cztery różne konstruktory typów, więc możemy go zainicjować zgodnie z naszym wymagania. Now using HashMap (int initialCapacity) constructor

    Map<String, String> hashMap = new HashMap<String, String>(3);
    hashMap.put("virat", "cricket");
    hashMap.put("amit","football");

Referencja: Jak utworzyć HashMap

  1. Singleton HashMaps using Kolekcje

      Map<String, String> immutableMap = Collections.singletonMap("rohit", 
           "cricket");
    
  2. Empty HashMaps using Collections

      Map<String, String> emptyMap = Collections.emptyMap();
    
  3. Anonimowa podklasa do tworzenia HashMap

       Map<String, String> map = new HashMap<String, String>() {{
         put("hcl", "amit");
         put("tcs","ravi");
         put("wipro","anmol");
        }};
    
 0
Author: Anuj Dhiman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-27 16:55:38