How to directly initialize a HashMap (in a literal way)?
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);
}
};
jens
Updated on February 17, 2022Comments
-
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 almost 13 yearsIt 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 almost 13 yearsyep, that is way I wrote about being careful and gave a link to the description.
-
michaelok about 11 yearsGreat link. The reference in that link to GreencoddsTenthRuleOfProgramming is worth the read.
-
Reinout van Rees over 10 yearsAlso, guava has ImmutableMap.builder.put("k1","v1").put("k2","v2").build();
-
Gewthen about 10 yearsImmutableMap is not the same as a HashMap, as it will fail on null values, whereas map HashMap will not.
-
Mark over 9 yearsThis is a feasible option for initializing a Map in an interface (where you cannot use a static block).
-
kommradHomer over 9 yearscan you add "as ImmutableMap.builder.put("k1","v1").put("k2","v2").build()" as the "of" method is limited to 5 pairs at maximum ?
-
Thiago about 9 yearsJust 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 almost 9 years
-
Michael almost 9 yearsThis won't work if you want to initial the elements in a function...
-
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 over 8 yearsSimple and to the point. I think this with an extended commentary section would be the best answer.
-
hello_its_me about 8 yearsWhy 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 almost 8 yearsThere are memory implications that should be noted though. blog.jooq.org/2014/12/08/…
-
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 almost 8 yearsYear 2016. I keep Googling the same question and coming to the same answer. Wish I could upvote each time..
-
udachny over 7 yearsI like the cleanliness of it, but it creates unnecessary anonymous class and has the problems described here: c2.com/cgi/wiki?DoubleBraceInitialization
-
Stan Sokolov over 7 yearsVery elegant! Nice
-
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 over 7 yearsI 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 almost 7 yearsbtw using
ImmutableMap.of
gives me anunchecked assignment
warning. -
skwisgaar almost 7 yearsand for the cases when you need a Map with a single entry there's
Collections.singletonMap()
:) -
Franklin Yu over 6 yearsNow that stable Java 9 has been released, I prefer this link for Javadoc. And +1 because one less dependency!
-
madhairsilence over 6 yearsThis cant be used when you have a variable inside. You have make it final
-
Brent Bradburn almost 6 yearsWhere is Java 9
entry
documented? -
yankee almost 6 years@nobar: In the very last link at the end of my post.
-
Gerold Broser over 5 yearsI wrote an answer inspired by yours: stackoverflow.com/questions/507602/…
-
Rolintocour over 5 yearsAnother 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 over 5 years"this works for up to 10 elements", what if we want 11 elements?
-
yankee over 5 years@MrCholo: In this case use one of the other possibilities.
-
Cameron Hudson over 5 yearsShould be
Map.entry
, notentry
, but works otherwise. Thanks! -
yankee over 5 years@CameronHudson: If you use a
static import
then it is justentry
. -
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 about 5 yearsthis is awesome Jens!
-
Thrasi about 5 years@yankee can you elaborate on "However, the anonymous subclass might introduce unwanted behaviour in some cases."?
-
yankee almost 5 years@Thrasi: I added two examples.
-
sudoz over 4 yearsBut guava's immutableMap only support 5 key-value pairs most.
-
ZhaoGang over 4 yearsCan anyone explain the synax here? The nested
{{}}
. -
Diego dos Santos over 4 yearsNice 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 over 4 yearsDouble 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 over 3 yearsAn elegant, and easy-to-understand example! And the Apache Utils is also great.
-
Tobias Grunwald almost 3 yearsIn case you are using apache commons, you could also use
Pair.of()
instead ofnew SimpleEntry<>
and thenPair::getKey
andPair::getValue
-
MarkHu almost 3 yearsIsn't this just a variant on the non-desirable old pre-Java9 method described in the most popular answer?
-
akim almost 3 yearsThe lightweight syntax for Java 9 is nice, but does not work when a key is null.
-
jox about 2 yearsAnother warning: A HashMap create this way may result in the string
"null"
when trying to serialize it to JSON vianew 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 about 2 years@yankee This question asks how to directly initialize a HashMap.
Collections.singletonMap()
doesn't work for this becauseHashMap
doesn't implement aCollection
. This can cause type errors in your code, and sinceMap
can't be typecast toHashMap
, or vice versa, this just won't work. -
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. WhateverCollections.singletonMap()
creates, it implements theMap
interface, because that's what its signature says. Not sure what you mean by "HashMap
doesn't implement aCollection
" -Map
does not inherit fromCollection
either, so I don't see how this is relevant. -
Mugen about 2 yearssimpler to use
entry(...)
overnew SimpleEntry<>(...)
(importjava.util.Map.entry
)