How to directly initialize a HashMap (in a literal way)?

1,547,171

Solution 1

All Versions

In case you happen to need just a single entry: There is Collections.singletonMap("key", "value").

For Java Version 9 or higher:

Yes, this is possible now. In Java 9 a couple of factory methods have been added that simplify the creation of maps :

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

In the example above both test and test2 will be the same, just with different ways of expressing the Map. The Map.of method is defined for up to ten elements in the map, while the Map.ofEntries method will have no such limit.

Note that in this case the resulting map will be an immutable map. If you want the map to be mutable, you could copy it again, e.g. using mutableMap = new HashMap<>(Map.of("a", "b"));

(See also JEP 269 and the Javadoc)

For up to Java Version 8:

No, you will have to add all the elements manually. You can use an initializer in an anonymous subclass to make the syntax a little bit shorter:

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

However, the anonymous subclass might introduce unwanted behavior in some cases. This includes for example:

  • It generates an additional class which increases memory consumption, disk space consumption and startup-time
  • In case of a non-static method: It holds a reference to the object the creating method was called upon. That means the object of the outer class cannot be garbage collected while the created map object is still referenced, thus blocking additional memory

Using a function for initialization will also enable you to generate a map in an initializer, but avoids nasty side-effects:

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

Solution 2

This is one way.

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

However, you should be careful and make sure that you understand the above code (it creates a new class that inherits from HashMap). Therefore, you should read more here: http://www.c2.com/cgi/wiki?DoubleBraceInitialization , or simply use Guava:

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

ImmutableMap.of works for up to 5 entries. Otherwise, use the builder: source.

Solution 3

If you allow 3rd party libs, you can use Guava's ImmutableMap to achieve literal-like brevity:

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

This works for up to 5 key/value pairs, otherwise you can use its builder:

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


  • note that Guava's ImmutableMap implementation differs from Java's HashMap implementation (most notably it is immutable and does not permit null keys/values)
  • for more info, see Guava's user guide article on its immutable collection types

Solution 4

There is no direct way to do this - Java has no Map literals (yet - I think they were proposed for Java 8).

Some people like this:

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

This creates an anonymous subclass of HashMap, whose instance initializer puts these values. (By the way, a map can't contain twice the same value, your second put will overwrite the first one. I'll use different values for the next examples.)

The normal way would be this (for a local variable):

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

If your test map is an instance variable, put the initialization in a constructor or instance initializer:

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

If your test map is a class variable, put the initialization in a static initializer:

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

If you want your map to never change, you should after the initialization wrap your map by Collections.unmodifiableMap(...). You can do this in a static initializer too:

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

(I'm not sure if you can now make test final ... try it out and report here.)

Solution 5

Map<String,String> test = new HashMap<String, String>()
{
    {
        put(key1, value1);
        put(key2, value2);
    }
};
Share:
1,547,171
jens
Author by

jens

Updated on February 17, 2022

Comments

  • jens
    jens about 2 years

    Is there some way of initializing a Java HashMap like this?:

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

    What would be the correct syntax? I have not found anything regarding this. Is this possible? I am looking for the shortest/fastest way to put some "final/static" values in a map that never change and are known in advance when creating the Map.

  • jprete
    jprete almost 13 years
    It works but it's ugly and has invisible side effects that the user should understand before doing it - for example, generating an entire anonymous class on the spot.
  • gregory561
    gregory561 almost 13 years
    yep, that is way I wrote about being careful and gave a link to the description.
  • michaelok
    michaelok about 11 years
    Great link. The reference in that link to GreencoddsTenthRuleOfProgramming is worth the read.
  • Reinout van Rees
    Reinout van Rees over 10 years
    Also, guava has ImmutableMap.builder.put("k1","v1").put("k2","v2").build();
  • Gewthen
    Gewthen about 10 years
    ImmutableMap is not the same as a HashMap, as it will fail on null values, whereas map HashMap will not.
  • Mark
    Mark over 9 years
    This is a feasible option for initializing a Map in an interface (where you cannot use a static block).
  • kommradHomer
    kommradHomer over 9 years
    can you add "as ImmutableMap.builder.put("k1","v1").put("k2","v2").build()" as the "of" method is limited to 5 pairs at maximum ?
  • Thiago
    Thiago about 9 years
    Just to help others that might face this issue. You have to type the builder to make it a Map<String, String>, like this: Map<String,String> test = ImmutableMap.<String,String>builder().put("k1", "v1").put("k2", "v2").build();
  • Dan Jay
    Dan Jay almost 9 years
  • Michael
    Michael almost 9 years
    This won't work if you want to initial the elements in a function...
  • yankee
    yankee almost 9 years
    @Michael: Well yes, if you want to use a function than you cannot use a not-function. But why do you want to?
  • ooolala
    ooolala over 8 years
    Simple and to the point. I think this with an extended commentary section would be the best answer.
  • hello_its_me
    hello_its_me about 8 years
    Why doesn't this have more votes? Is it not better than the other answers? I looks a lot cleaner. Could someone explain to me, please? Because I might end up using this one. Thanks.
  • Alkanshel
    Alkanshel almost 8 years
    There are memory implications that should be noted though. blog.jooq.org/2014/12/08/…
  • Paŭlo Ebermann
    Paŭlo Ebermann almost 8 years
    @Amalgovinus Basically, by creating a new subclass, you are hard-coding the type arguments from HashMap into this subclass. This can only work if you actually provide them. (With a new (empty) HashMap, the type arguments are not relevant.)
  • saiyancoder
    saiyancoder almost 8 years
    Year 2016. I keep Googling the same question and coming to the same answer. Wish I could upvote each time..
  • udachny
    udachny over 7 years
    I like the cleanliness of it, but it creates unnecessary anonymous class and has the problems described here: c2.com/cgi/wiki?DoubleBraceInitialization
  • Stan Sokolov
    Stan Sokolov over 7 years
    Very elegant! Nice
  • Daniel Hári
    Daniel Hári over 7 years
    @hello_its_me: Because Its same as stackoverflow.com/a/6802512/1386911 answer, just the formatting different. And in this case this extended formatting has no additional value on top of compact format for readability.
  • Androidcoder
    Androidcoder over 7 years
    I use this method to send data to the Firebase database. If you don't create a new Hashmap for each 'setValue' you can get concurrent access exceptions.
  • Yar
    Yar almost 7 years
    btw using ImmutableMap.of gives me an unchecked assignment warning.
  • skwisgaar
    skwisgaar almost 7 years
    and for the cases when you need a Map with a single entry there's Collections.singletonMap() :)
  • Franklin Yu
    Franklin Yu over 6 years
    Now that stable Java 9 has been released, I prefer this link for Javadoc. And +1 because one less dependency!
  • madhairsilence
    madhairsilence over 6 years
    This cant be used when you have a variable inside. You have make it final
  • Brent Bradburn
    Brent Bradburn almost 6 years
    Where is Java 9 entry documented?
  • yankee
    yankee almost 6 years
    @nobar: In the very last link at the end of my post.
  • Gerold Broser
    Gerold Broser over 5 years
    I wrote an answer inspired by yours: stackoverflow.com/questions/507602/…
  • Rolintocour
    Rolintocour over 5 years
    Another solution with Apache Utils that is never mentioned but is readable, using prior Java versions: MapUtils.putAll(new HashMap<String, String>(), new Object[] { "My key", "my value", ...
  • Admin
    Admin over 5 years
    "this works for up to 10 elements", what if we want 11 elements?
  • yankee
    yankee over 5 years
    @MrCholo: In this case use one of the other possibilities.
  • Cameron Hudson
    Cameron Hudson over 5 years
    Should be Map.entry, not entry, but works otherwise. Thanks!
  • yankee
    yankee over 5 years
    @CameronHudson: If you use a static import then it is just entry.
  • Cameron Hudson
    Cameron Hudson over 5 years
    @yankee Oh thanks, TIL. Here is some more info for those like me who use the Eclipse default of non-static imports: geeksforgeeks.org/static-import-java
  • Gaurav
    Gaurav about 5 years
    this is awesome Jens!
  • Thrasi
    Thrasi about 5 years
    @yankee can you elaborate on "However, the anonymous subclass might introduce unwanted behaviour in some cases."?
  • yankee
    yankee almost 5 years
    @Thrasi: I added two examples.
  • sudoz
    sudoz over 4 years
    But guava's immutableMap only support 5 key-value pairs most.
  • ZhaoGang
    ZhaoGang over 4 years
    Can anyone explain the synax here? The nested {{}} .
  • Diego dos Santos
    Diego dos Santos over 4 years
    Nice answer. Keep in mind that, as the doc states, Map.entry accepts neither null key nor null value, so it's not recommended for cases where values might be null.
  • Yossarian42
    Yossarian42 over 4 years
    Double curly initialization is creating an anonymous class, thus contains a reference to the outer class and will sometimes cause the outer class to exist even after it should be garbage collected. So it will cause a memory leak.
  • Tihamer
    Tihamer over 3 years
    An elegant, and easy-to-understand example! And the Apache Utils is also great.
  • Tobias Grunwald
    Tobias Grunwald almost 3 years
    In case you are using apache commons, you could also use Pair.of() instead of new SimpleEntry<> and then Pair::getKey and Pair::getValue
  • MarkHu
    MarkHu almost 3 years
    Isn't this just a variant on the non-desirable old pre-Java9 method described in the most popular answer?
  • akim
    akim almost 3 years
    The lightweight syntax for Java 9 is nice, but does not work when a key is null.
  • jox
    jox about 2 years
    Another warning: A HashMap create this way may result in the string "null" when trying to serialize it to JSON via new Gson().toJson(h). (Side node: getClass() on a normal HashMap object will return "HashMap". But on an object created like this it will be something like "Main$1" (an anonymous class as mentioned by others)).
  • skidwiz
    skidwiz about 2 years
    @yankee This question asks how to directly initialize a HashMap. Collections.singletonMap() doesn't work for this because HashMap doesn't implement a Collection. This can cause type errors in your code, and since Map can't be typecast to HashMap, or vice versa, this just won't work.
  • Frans
    Frans about 2 years
    @skidwiz The original question should probably be reworded - I don't think the question asker is particularly interested in the actual implementation of map, as long as it's a map, i.e. is an instance of a concrete class that implements the Map interface. Whatever Collections.singletonMap() creates, it implements the Map interface, because that's what its signature says. Not sure what you mean by "HashMap doesn't implement a Collection" - Map does not inherit from Collection either, so I don't see how this is relevant.
  • Mugen
    Mugen about 2 years
    simpler to use entry(...) over new SimpleEntry<>(...) (import java.util.Map.entry)