How would you initialise a static Map
in Java?
Method one: static initialiser
Method two: instance initialiser (anonymous subclass)
or
some other method?
What are the pros and cons of each?
Here is an example illustrating the two methods:
import java.util.HashMap;
import java.util.Map;
public class Test {
private static final Map<Integer, String> myMap = new HashMap<>();
static {
myMap.put(1, "one");
myMap.put(2, "two");
}
private static final Map<Integer, String> myMap2 = new HashMap<>(){
{
put(1, "one");
put(2, "two");
}
};
}
This question is related to
java
dictionary
collections
initialization
idioms
With Java 8 I've come to use the following pattern:
private static final Map<String, Integer> MAP = Stream.of(
new AbstractMap.SimpleImmutableEntry<>("key1", 1),
new AbstractMap.SimpleImmutableEntry<>("key2", 2)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
It's not the most terse and a bit roundabout, but
java.util
Maybe it's interesting to check out Google Collections, e.g. the videos that they have on their page. They provide various ways to initialize maps and sets, and provide immutable collections as well.
Update: This library is now named Guava.
Because Java does not support map literals, map instances must always be explicitly instantiated and populated.
Fortunately, it is possible to approximate the behavior of map literals in Java using factory methods.
For example:
public class LiteralMapFactory {
// Creates a map from a list of entries
@SafeVarargs
public static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {
LinkedHashMap<K, V> map = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
// Creates a map entry
public static <K, V> Map.Entry<K, V> entry(K key, V value) {
return new AbstractMap.SimpleEntry<>(key, value);
}
public static void main(String[] args) {
System.out.println(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));
}
}
Output:
{a=1, b=2, c=3}
It is a lot more convenient than creating and populating the map an element at a time.
The second method could invoke protected methods if needed. This can be useful for initializing classes which are immutable after construction.
I would never create an anonymous subclass in this situation. Static initializers work equally well, if you would like to make the map unmodifiable for example:
private static final Map<Integer, String> MY_MAP;
static
{
Map<Integer, String>tempMap = new HashMap<Integer, String>();
tempMap.put(1, "one");
tempMap.put(2, "two");
MY_MAP = Collections.unmodifiableMap(tempMap);
}
Here's a Java 8 one-line static map initializer:
private static final Map<String, String> EXTENSION_TO_MIMETYPE =
Arrays.stream(new String[][] {
{ "txt", "text/plain" },
{ "html", "text/html" },
{ "js", "application/javascript" },
{ "css", "text/css" },
{ "xml", "application/xml" },
{ "png", "image/png" },
{ "gif", "image/gif" },
{ "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" },
{ "svg", "image/svg+xml" },
}).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));
Edit: to initialize a Map<Integer, String>
as in the question, you'd need something like this:
static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
{1, "one"},
{2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));
Edit(2): There is a better, mixed-type-capable version by i_am_zero that uses a stream of new SimpleEntry<>(k, v)
calls. Check out that answer: https://stackoverflow.com/a/37384773/3950982
If you want something terse and relatively safe, you can just shift compile-time type checking to run-time:
static final Map<String, Integer> map = MapUtils.unmodifiableMap(
String.class, Integer.class,
"cat", 4,
"dog", 2,
"frog", 17
);
This implementation should catch any errors:
import java.util.HashMap;
public abstract class MapUtils
{
private MapUtils() { }
public static <K, V> HashMap<K, V> unmodifiableMap(
Class<? extends K> keyClazz,
Class<? extends V> valClazz,
Object...keyValues)
{
return Collections.<K, V>unmodifiableMap(makeMap(
keyClazz,
valClazz,
keyValues));
}
public static <K, V> HashMap<K, V> makeMap(
Class<? extends K> keyClazz,
Class<? extends V> valClazz,
Object...keyValues)
{
if (keyValues.length % 2 != 0)
{
throw new IllegalArgumentException(
"'keyValues' was formatted incorrectly! "
+ "(Expected an even length, but found '" + keyValues.length + "')");
}
HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);
for (int i = 0; i < keyValues.length;)
{
K key = cast(keyClazz, keyValues[i], i);
++i;
V val = cast(valClazz, keyValues[i], i);
++i;
result.put(key, val);
}
return result;
}
private static <T> T cast(Class<? extends T> clazz, Object object, int i)
{
try
{
return clazz.cast(object);
}
catch (ClassCastException e)
{
String objectName = (i % 2 == 0) ? "Key" : "Value";
String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
}
}
}
Maybe it's interesting to check out Google Collections, e.g. the videos that they have on their page. They provide various ways to initialize maps and sets, and provide immutable collections as well.
Update: This library is now named Guava.
I like the anonymous class syntax; it's just less code. However, one major con I have found is that you won't be able to serialize that object via remoting. You will get an exception about not being able to find the anonymous class on the remote side.
I do not like Static initializer syntax and I'm not convinced to anonymous subclasses. Generally, I agree with all cons of using Static initializers and all cons of using anonymous subclasses that were mentioned in previus answers. On the other hand - pros presented in these posts are not enough for me. I prefer to use static initialization method:
public class MyClass {
private static final Map<Integer, String> myMap = prepareMap();
private static Map<Integer, String> prepareMap() {
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "one");
hashMap.put(2, "two");
return hashMap;
}
}
There are some good answers here, but I do want to offer one more.
Create your own static method to create and initialize a Map
. I have my own CollectionUtils
class in a package that I use across projects with various utilities that I use regularly that are easy for me to write and avoids the need for a dependency on some larger library.
Here's my newMap
method:
public class CollectionUtils {
public static Map newMap(Object... keyValuePairs) {
Map map = new HashMap();
if ( keyValuePairs.length % 2 == 1 ) throw new IllegalArgumentException("Must have even number of arguments");
for ( int i=0; i<keyValuePairs.length; i+=2 ) {
map.put(keyValuePairs[i], keyValuePairs[i + 1]);
}
return map;
}
}
Usage:
import static CollectionUtils.newMap;
// ...
Map aMap = newMap("key1", 1.23, "key2", 2.34);
Map bMap = newMap(objKey1, objVal1, objKey2, objVal2, objKey3, objVal3);
// etc...
It doesn't make use of generics, but you can typecast the map as you wish (just be sure you typecast it correctly!)
Map<String,Double> aMap = (Map<String,Double>)newMap("key1", 1.23, "key2", 2.34);
I would never create an anonymous subclass in this situation. Static initializers work equally well, if you would like to make the map unmodifiable for example:
private static final Map<Integer, String> MY_MAP;
static
{
Map<Integer, String>tempMap = new HashMap<Integer, String>();
tempMap.put(1, "one");
tempMap.put(2, "two");
MY_MAP = Collections.unmodifiableMap(tempMap);
}
The second method could invoke protected methods if needed. This can be useful for initializing classes which are immutable after construction.
I would use:
public class Test {
private static final Map<Integer, String> MY_MAP = createMap();
private static Map<Integer, String> createMap() {
Map<Integer, String> result = new HashMap<>();
result.put(1, "one");
result.put(2, "two");
return Collections.unmodifiableMap(result);
}
}
The anonymous class you're creating works well. However you should be aware that this is an inner class and as such, it'll contain a reference to the surrounding class instance. So you'll find you can't do certain things with it (using XStream for one). You'll get some very strange errors.
Having said that, so long as you're aware then this approach is fine. I use it most of the time for initialising all sorts of collections in a concise fashion.
EDIT: Pointed out correctly in the comments that this is a static class. Obviously I didn't read this closely enough. However my comments do still apply to anonymous inner classes.
Here's my favorite if I
ImmutableMap.of()
Map
Map.of()
from JDK9+public static <A> Map<String, A> asMap(Object... keysAndValues) {
return new LinkedHashMap<String, A>() {{
for (int i = 0; i < keysAndValues.length - 1; i++) {
put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
}
}};
}
It's very compact, and it ignores stray values (i.e. a final key without a value).
Usage:
Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));
I've read the answers and i decided to write my own map builder. Feel free to copy-paste and enjoy.
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* A tool for easy creation of a map. Code example:<br/>
* {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
* @param <K> key type (inferred by constructor)
* @param <V> value type (inferred by constructor)
* @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
*/
public class MapBuilder <K, V> {
private Map<K, V> map = new HashMap<>();
/** Constructor that also enters the first entry. */
private MapBuilder(K key, V value) {
and(key, value);
}
/** Factory method that creates the builder and enters the first entry. */
public static <A, B> MapBuilder<A, B> mapOf(A key, B value) {
return new MapBuilder<>(key, value);
}
/** Puts the key-value pair to the map and returns itself for method chaining */
public MapBuilder<K, V> and(K key, V value) {
map.put(key, value);
return this;
}
/**
* If no reference to builder is kept and both the key and value types are immutable,
* the resulting map is immutable.
* @return contents of MapBuilder as an unmodifiable map.
*/
public Map<K, V> build() {
return Collections.unmodifiableMap(map);
}
}
EDIT: Lately, I keep finding public static method of
pretty often and I kinda like it. I added it into the code and made the constructor private, thus switching to static factory method pattern.
EDIT2: Even more recently, I no longer like static method called of
, as it looks pretty bad when using static imports. I renamed it to mapOf
instead, making it more suitable for static imports.
If you want unmodifiable map, finally java 9 added a cool factory method of
to Map
interface. Similar method is added to Set, List as well.
Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
With Eclipse Collections, all of the following will work:
import java.util.Map;
import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;
public class StaticMapsTest
{
private static final Map<Integer, String> MAP =
Maps.mutable.with(1, "one", 2, "two");
private static final MutableMap<Integer, String> MUTABLE_MAP =
Maps.mutable.with(1, "one", 2, "two");
private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();
private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
Maps.mutable.with(1, "one", 2, "two").asSynchronized();
private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
Maps.mutable.with(1, "one", 2, "two").toImmutable();
private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
Maps.immutable.with(1, "one", 2, "two");
}
You can also statically initialize primitive maps with Eclipse Collections.
import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;
public class StaticPrimitiveMapsTest
{
private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two");
private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.asUnmodifiable();
private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.asSynchronized();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.toImmutable();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
IntObjectMaps.immutable.<String>empty()
.newWithKeyValue(1, "one")
.newWithKeyValue(2, "two");
}
Note: I am a committer for Eclipse Collections
I've done something a bit different. Not the best, but it works for me. Maybe it could be "genericized".
private static final Object[][] ENTRIES =
{
{new Integer(1), "one"},
{new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);
private static Map newMap(Object[][] entries)
{
Map map = new HashMap();
for (int x = 0; x < entries.length; x++)
{
Object[] entry = entries[x];
map.put(entry[0], entry[1]);
}
return map;
}
I like anonymous class, because it is easy to deal with it:
public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
{
put(1, "some value");
//rest of code here
}
});
I like using the static initializer "technique" when I have a concrete realization of an abstract class that has defined an initializing constructor but no default constructor but I want my subclass to have a default constructor.
For example:
public abstract class Shape {
public static final String COLOR_KEY = "color_key";
public static final String OPAQUE_KEY = "opaque_key";
private final String color;
private final Boolean opaque;
/**
* Initializing constructor - note no default constructor.
*
* @param properties a collection of Shape properties
*/
public Shape(Map<String, Object> properties) {
color = ((String) properties.getOrDefault(COLOR_KEY, "black"));
opaque = (Boolean) properties.getOrDefault(OPAQUE_KEY, false);
}
/**
* Color property accessor method.
*
* @return the color of this Shape
*/
public String getColor() {
return color;
}
/**
* Opaque property accessor method.
*
* @return true if this Shape is opaque, false otherwise
*/
public Boolean isOpaque() {
return opaque;
}
}
and my concrete realization of this class -- but it wants/needs a default constructor:
public class SquareShapeImpl extends Shape {
private static final Map<String, Object> DEFAULT_PROPS = new HashMap<>();
static {
DEFAULT_PROPS.put(Shape.COLOR_KEY, "yellow");
DEFAULT_PROPS.put(Shape.OPAQUE_KEY, false);
}
/**
* Default constructor -- intializes this square to be a translucent yellow
*/
public SquareShapeImpl() {
// the static initializer was useful here because the call to
// this(...) must be the first statement in this constructor
// i.e., we can't be mucking around and creating a map here
this(DEFAULT_PROPS);
}
/**
* Initializing constructor -- create a Square with the given
* collection of properties.
*
* @param props a collection of properties for this SquareShapeImpl
*/
public SquareShapeImpl(Map<String, Object> props) {
super(props);
}
}
then to use this default constructor, we simply do:
public class StaticInitDemo {
public static void main(String[] args) {
// create a translucent, yellow square...
Shape defaultSquare = new SquareShapeImpl();
// etc...
}
}
The anonymous class you're creating works well. However you should be aware that this is an inner class and as such, it'll contain a reference to the surrounding class instance. So you'll find you can't do certain things with it (using XStream for one). You'll get some very strange errors.
Having said that, so long as you're aware then this approach is fine. I use it most of the time for initialising all sorts of collections in a concise fashion.
EDIT: Pointed out correctly in the comments that this is a static class. Obviously I didn't read this closely enough. However my comments do still apply to anonymous inner classes.
Note: This answer actually belongs to question How to directly initialize a HashMap (in a literal way)? but since that's marked as duplicate of this one...
Prior to Java 9 with its Map.of() (which is also limited to 10 mappings) you can extend a Map
implementation of your choice, e.g.:
public class InitHashMap<K, V> extends HashMap<K, V>
re-implement HashMap
's constructors:
public InitHashMap() {
super();
}
public InitHashMap( int initialCapacity, float loadFactor ) {
super( initialCapacity, loadFactor );
}
public InitHashMap( int initialCapacity ) {
super( initialCapacity );
}
public InitHashMap( Map<? extends K, ? extends V> map ) {
super( map );
}
and add an additional constructor that's inspired by Aerthel's answer but is generic by using Object...
and <K, V>
types:
public InitHashMap( final Object... keyValuePairs ) {
if ( keyValuePairs.length >>> 1 != 0 )
throw new IllegalArgumentException( "Uneven number of arguments." );
K key = null;
int i = -1;
for ( final Object keyOrValue : keyValuePairs )
switch ( ++i >>> 1 ) {
case 0: // key
if ( keyOrValue == null )
throw new IllegalArgumentException( "Key[" + (i >>> 1) + "] is <null>." );
key = (K) keyOrValue;
continue;
case 1: // value
put( key, (V) keyOrValue );
}
}
public static void main( final String[] args ) {
final Map<Integer, String> map = new InitHashMap<>( 1, "First", 2, "Second", 3, "Third" );
System.out.println( map );
}
{1=First, 2=Second, 3=Third}
You also can extend the Map
interface likewise:
public interface InitMap<K, V> extends Map<K, V> {
static <K, V> Map<K, V> of( final Object... keyValuePairs ) {
if ( keyValuePairs.length >>> 1 != 0 )
throw new IllegalArgumentException( "Uneven number of arguments." );
final Map<K, V> map = new HashMap<>( keyValuePairs.length >>> 1, .75f );
K key = null;
int i = -1;
for ( final Object keyOrValue : keyValuePairs )
switch ( ++i >>> 1 ) {
case 0: // key
if ( keyOrValue == null )
throw new IllegalArgumentException( "Key[" + (i >>> 1) + "] is <null>." );
key = (K) keyOrValue;
continue;
case 1: // value
map.put( key, (V) keyOrValue );
}
return map;
}
}
public static void main( final String[] args ) {
System.out.println( InitMap.of( 1, "First", 2, "Second", 3, "Third" ) );
}
{1=First, 2=Second, 3=Third}
The anonymous class you're creating works well. However you should be aware that this is an inner class and as such, it'll contain a reference to the surrounding class instance. So you'll find you can't do certain things with it (using XStream for one). You'll get some very strange errors.
Having said that, so long as you're aware then this approach is fine. I use it most of the time for initialising all sorts of collections in a concise fashion.
EDIT: Pointed out correctly in the comments that this is a static class. Obviously I didn't read this closely enough. However my comments do still apply to anonymous inner classes.
With Eclipse Collections, all of the following will work:
import java.util.Map;
import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;
public class StaticMapsTest
{
private static final Map<Integer, String> MAP =
Maps.mutable.with(1, "one", 2, "two");
private static final MutableMap<Integer, String> MUTABLE_MAP =
Maps.mutable.with(1, "one", 2, "two");
private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();
private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
Maps.mutable.with(1, "one", 2, "two").asSynchronized();
private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
Maps.mutable.with(1, "one", 2, "two").toImmutable();
private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
Maps.immutable.with(1, "one", 2, "two");
}
You can also statically initialize primitive maps with Eclipse Collections.
import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;
public class StaticPrimitiveMapsTest
{
private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two");
private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.asUnmodifiable();
private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.asSynchronized();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.toImmutable();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
IntObjectMaps.immutable.<String>empty()
.newWithKeyValue(1, "one")
.newWithKeyValue(2, "two");
}
Note: I am a committer for Eclipse Collections
Well... I like enums ;)
enum MyEnum {
ONE (1, "one"),
TWO (2, "two"),
THREE (3, "three");
int value;
String name;
MyEnum(int value, String name) {
this.value = value;
this.name = name;
}
static final Map<Integer, String> MAP = Stream.of( values() )
.collect( Collectors.toMap( e -> e.value, e -> e.name ) );
}
One advantage to the second method is that you can wrap it with Collections.unmodifiableMap()
to guarantee that nothing is going to update the collection later:
private static final Map<Integer, String> CONSTANT_MAP =
Collections.unmodifiableMap(new HashMap<Integer, String>() {{
put(1, "one");
put(2, "two");
}});
// later on...
CONSTANT_MAP.put(3, "three"); // going to throw an exception!
This one uses Apache commons-lang which will most likely be on your class path already:
Map<String, String> collect = Stream.of(
Pair.of("hello", "world"),
Pair.of("abc", "123"),
Pair.of("java", "eight")
).collect(Collectors.toMap(Pair::getKey, Pair::getValue));
I have not seen the approach I use (and have grown to like) posted in any answers, so here it is:
I don't like using static initializers because they are clunky, and I don't like anonymous classes because it is creating a new class for each instance.
instead, I prefer initialization that looks like this:
map(
entry("keyA", "val1"),
entry("keyB", "val2"),
entry("keyC", "val3")
);
unfortunately, these methods are not part of the standard Java library, so you will need to create (or use) a utility library that defines the following methods:
public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)
public static <K,V> Map.Entry<K,V> entry(K key, V val)
(you can use 'import static' to avoid needing to prefix the method's name)
I found it useful to provide similar static methods for the other collections (list, set, sortedSet, sortedMap, etc.)
Its not quite as nice as json object initialization, but it's a step in that direction, as far as readability is concerned.
Here is the code by AbacusUtil
Map<Integer, String> map = N.asMap(1, "one", 2, "two");
// Or for Immutable map
ImmutableMap<Integer, String> = ImmutableMap.of(1, "one", 2, "two");
Declaration: I'm the developer of AbacusUtil.
I would use:
public class Test {
private static final Map<Integer, String> MY_MAP = createMap();
private static Map<Integer, String> createMap() {
Map<Integer, String> result = new HashMap<>();
result.put(1, "one");
result.put(2, "two");
return Collections.unmodifiableMap(result);
}
}
The second method could invoke protected methods if needed. This can be useful for initializing classes which are immutable after construction.
I've done something a bit different. Not the best, but it works for me. Maybe it could be "genericized".
private static final Object[][] ENTRIES =
{
{new Integer(1), "one"},
{new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);
private static Map newMap(Object[][] entries)
{
Map map = new HashMap();
for (int x = 0; x < entries.length; x++)
{
Object[] entry = entries[x];
map.put(entry[0], entry[1]);
}
return map;
}
The second method could invoke protected methods if needed. This can be useful for initializing classes which are immutable after construction.
There are some good answers here, but I do want to offer one more.
Create your own static method to create and initialize a Map
. I have my own CollectionUtils
class in a package that I use across projects with various utilities that I use regularly that are easy for me to write and avoids the need for a dependency on some larger library.
Here's my newMap
method:
public class CollectionUtils {
public static Map newMap(Object... keyValuePairs) {
Map map = new HashMap();
if ( keyValuePairs.length % 2 == 1 ) throw new IllegalArgumentException("Must have even number of arguments");
for ( int i=0; i<keyValuePairs.length; i+=2 ) {
map.put(keyValuePairs[i], keyValuePairs[i + 1]);
}
return map;
}
}
Usage:
import static CollectionUtils.newMap;
// ...
Map aMap = newMap("key1", 1.23, "key2", 2.34);
Map bMap = newMap(objKey1, objVal1, objKey2, objVal2, objKey3, objVal3);
// etc...
It doesn't make use of generics, but you can typecast the map as you wish (just be sure you typecast it correctly!)
Map<String,Double> aMap = (Map<String,Double>)newMap("key1", 1.23, "key2", 2.34);
In Java 8, procedural approach can also be wrapped in Supplier
:
Map<String,String> m = ((Supplier<Map<String,String>>)(() -> {
Map<String,String> result = new HashMap<>();
result.put("foo","hoo");
...
return result;
)).get();
It's only hypothetical way but can come handy if you really need one-liner.
Java 8 with streams:
private static final Map<String, TemplateOpts> templates = new HashMap<>();
static {
Arrays.stream(new String[][]{
{CUSTOMER_CSV, "Plantilla cliente", "csv"}
}).forEach(f -> templates.put(f[0], new TemplateOpts(f[1], f[2])));
}
It can be also a Object[][] to put anything inside and map it in the forEach loop
Maybe it's interesting to check out Google Collections, e.g. the videos that they have on their page. They provide various ways to initialize maps and sets, and provide immutable collections as well.
Update: This library is now named Guava.
Java 8 with streams:
private static final Map<String, TemplateOpts> templates = new HashMap<>();
static {
Arrays.stream(new String[][]{
{CUSTOMER_CSV, "Plantilla cliente", "csv"}
}).forEach(f -> templates.put(f[0], new TemplateOpts(f[1], f[2])));
}
It can be also a Object[][] to put anything inside and map it in the forEach loop
Now that Java 8 is out, this question warrants revisiting. I took a stab at it -- looks like maybe you can exploit lambda expression syntax to get a pretty nice and concise (but type-safe) map literal syntax that looks like this:
Map<String,Object> myMap = hashMap(
bob -> 5,
TheGimp -> 8,
incredibleKoolAid -> "James Taylor",
heyArnold -> new Date()
);
Map<String,Integer> typesafeMap = treeMap(
a -> 5,
bee -> 8,
sea -> 13
deep -> 21
);
Untested sample code at https://gist.github.com/galdosd/10823529 Would be curious about the opinions of others on this (it's mildly evil...)
I prefer using a static initializer to avoid generating anonymous classes (which would have no further purpose), so I'll list tips initializing with a static initializer. All listed solutions / tips are type-safe.
Note: The question doesn't say anything about making the map unmodifiable, so I will leave that out, but know that it can easily be done with Collections.unmodifiableMap(map)
.
First tip
The 1st tip is that you can make a local reference to the map and you give it a SHORT name:
private static final Map<Integer, String> myMap = new HashMap<>();
static {
final Map<Integer, String> m = myMap; // Use short name!
m.put(1, "one"); // Here referencing the local variable which is also faster!
m.put(2, "two");
m.put(3, "three");
}
Second tip
The 2nd tip is that you can create a helper method to add entries; you can also make this helper method public if you want to:
private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
p(1, "one"); // Calling the helper method.
p(2, "two");
p(3, "three");
}
private static void p(Integer k, String v) {
myMap2.put(k, v);
}
The helper method here is not re-usable though because it can only add elements to myMap2
. To make it re-usable, we could make the map itself a parameter of the helper method, but then initialization code would not be any shorter.
Third tip
The 3rd tip is that you can create a re-usable builder-like helper class with the populating functionality. This is really a simple, 10-line helper class which is type-safe:
public class Test {
private static final Map<Integer, String> myMap3 = new HashMap<>();
static {
new B<>(myMap3) // Instantiating the helper class with our map
.p(1, "one")
.p(2, "two")
.p(3, "three");
}
}
class B<K, V> {
private final Map<K, V> m;
public B(Map<K, V> m) {
this.m = m;
}
public B<K, V> p(K k, V v) {
m.put(k, v);
return this; // Return this for chaining
}
}
If you only need to add one value to the map you can use Collections.singletonMap:
Map<K, V> map = Collections.singletonMap(key, value)
With Java 8 I've come to use the following pattern:
private static final Map<String, Integer> MAP = Stream.of(
new AbstractMap.SimpleImmutableEntry<>("key1", 1),
new AbstractMap.SimpleImmutableEntry<>("key2", 2)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
It's not the most terse and a bit roundabout, but
java.util
I like anonymous class, because it is easy to deal with it:
public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
{
put(1, "some value");
//rest of code here
}
});
Here's my favorite if I
ImmutableMap.of()
Map
Map.of()
from JDK9+public static <A> Map<String, A> asMap(Object... keysAndValues) {
return new LinkedHashMap<String, A>() {{
for (int i = 0; i < keysAndValues.length - 1; i++) {
put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
}
}};
}
It's very compact, and it ignores stray values (i.e. a final key without a value).
Usage:
Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));
I like the Guava way of initialising a static, immutable map:
static final Map<Integer, String> MY_MAP = ImmutableMap.of(
1, "one",
2, "two"
);
As you can see, it's very concise (because of the convenient factory methods in ImmutableMap
).
If you want the map to have more than 5 entries, you can no longer use ImmutableMap.of()
. Instead, try ImmutableMap.builder()
along these lines:
static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
.put(1, "one")
.put(2, "two")
// ...
.put(15, "fifteen")
.build();
To learn more about the benefits of Guava's immutable collection utilities, see Immutable Collections Explained in Guava User Guide.
(A subset of) Guava used to be called Google Collections. If you aren't using this library in your Java project yet, I strongly recommend trying it out! Guava has quickly become one of the most popular and useful free 3rd party libs for Java, as fellow SO users agree. (If you are new to it, there are some excellent learning resources behind that link.)
Update (2015): As for Java 8, well, I would still use the Guava approach because it is way cleaner than anything else. If you don't want Guava dependency, consider a plain old init method. The hack with two-dimensional array and Stream API is pretty ugly if you ask me, and gets uglier if you need to create a Map whose keys and values are not the same type (like Map<Integer, String>
in the question).
As for future of Guava in general, with regards to Java 8, Louis Wasserman said this back in 2014, and [update] in 2016 it was announced that Guava 21 will require and properly support Java 8.
Update (2016): As Tagir Valeev points out, Java 9 will finally make this clean to do using nothing but pure JDK, by adding convenience factory methods for collections:
static final Map<Integer, String> MY_MAP = Map.of(
1, "one",
2, "two"
);
Map.of
in Java 9+private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");
See JEP 269 for details. JDK 9 reached general availability in September 2017.
If you only need to add one value to the map you can use Collections.singletonMap:
Map<K, V> map = Collections.singletonMap(key, value)
I've read the answers and i decided to write my own map builder. Feel free to copy-paste and enjoy.
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* A tool for easy creation of a map. Code example:<br/>
* {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
* @param <K> key type (inferred by constructor)
* @param <V> value type (inferred by constructor)
* @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
*/
public class MapBuilder <K, V> {
private Map<K, V> map = new HashMap<>();
/** Constructor that also enters the first entry. */
private MapBuilder(K key, V value) {
and(key, value);
}
/** Factory method that creates the builder and enters the first entry. */
public static <A, B> MapBuilder<A, B> mapOf(A key, B value) {
return new MapBuilder<>(key, value);
}
/** Puts the key-value pair to the map and returns itself for method chaining */
public MapBuilder<K, V> and(K key, V value) {
map.put(key, value);
return this;
}
/**
* If no reference to builder is kept and both the key and value types are immutable,
* the resulting map is immutable.
* @return contents of MapBuilder as an unmodifiable map.
*/
public Map<K, V> build() {
return Collections.unmodifiableMap(map);
}
}
EDIT: Lately, I keep finding public static method of
pretty often and I kinda like it. I added it into the code and made the constructor private, thus switching to static factory method pattern.
EDIT2: Even more recently, I no longer like static method called of
, as it looks pretty bad when using static imports. I renamed it to mapOf
instead, making it more suitable for static imports.
One advantage to the second method is that you can wrap it with Collections.unmodifiableMap()
to guarantee that nothing is going to update the collection later:
private static final Map<Integer, String> CONSTANT_MAP =
Collections.unmodifiableMap(new HashMap<Integer, String>() {{
put(1, "one");
put(2, "two");
}});
// later on...
CONSTANT_MAP.put(3, "three"); // going to throw an exception!
Maybe it's interesting to check out Google Collections, e.g. the videos that they have on their page. They provide various ways to initialize maps and sets, and provide immutable collections as well.
Update: This library is now named Guava.
JEP 269 provides some convenience factory methods for Collections API. This factory methods are not in current Java version, which is 8, but are planned for Java 9 release.
For Map
there are two factory methods: of
and ofEntries
. Using of
, you can pass alternating key/value pairs. For example, in order to create a Map
like {age: 27, major: cs}
:
Map<String, Object> info = Map.of("age", 27, "major", "cs");
Currently there are ten overloaded versions for of
, so you can create a map containing ten key/value pairs. If you don't like this limitation or alternating key/values, you can use ofEntries
:
Map<String, Object> info = Map.ofEntries(
Map.entry("age", 27),
Map.entry("major", "cs")
);
Both of
and ofEntries
will return an immutable Map
, so you can't change their elements after construction. You can try out these features using JDK 9 Early Access.
I do not like Static initializer syntax and I'm not convinced to anonymous subclasses. Generally, I agree with all cons of using Static initializers and all cons of using anonymous subclasses that were mentioned in previus answers. On the other hand - pros presented in these posts are not enough for me. I prefer to use static initialization method:
public class MyClass {
private static final Map<Integer, String> myMap = prepareMap();
private static Map<Integer, String> prepareMap() {
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "one");
hashMap.put(2, "two");
return hashMap;
}
}
I like using the static initializer "technique" when I have a concrete realization of an abstract class that has defined an initializing constructor but no default constructor but I want my subclass to have a default constructor.
For example:
public abstract class Shape {
public static final String COLOR_KEY = "color_key";
public static final String OPAQUE_KEY = "opaque_key";
private final String color;
private final Boolean opaque;
/**
* Initializing constructor - note no default constructor.
*
* @param properties a collection of Shape properties
*/
public Shape(Map<String, Object> properties) {
color = ((String) properties.getOrDefault(COLOR_KEY, "black"));
opaque = (Boolean) properties.getOrDefault(OPAQUE_KEY, false);
}
/**
* Color property accessor method.
*
* @return the color of this Shape
*/
public String getColor() {
return color;
}
/**
* Opaque property accessor method.
*
* @return true if this Shape is opaque, false otherwise
*/
public Boolean isOpaque() {
return opaque;
}
}
and my concrete realization of this class -- but it wants/needs a default constructor:
public class SquareShapeImpl extends Shape {
private static final Map<String, Object> DEFAULT_PROPS = new HashMap<>();
static {
DEFAULT_PROPS.put(Shape.COLOR_KEY, "yellow");
DEFAULT_PROPS.put(Shape.OPAQUE_KEY, false);
}
/**
* Default constructor -- intializes this square to be a translucent yellow
*/
public SquareShapeImpl() {
// the static initializer was useful here because the call to
// this(...) must be the first statement in this constructor
// i.e., we can't be mucking around and creating a map here
this(DEFAULT_PROPS);
}
/**
* Initializing constructor -- create a Square with the given
* collection of properties.
*
* @param props a collection of properties for this SquareShapeImpl
*/
public SquareShapeImpl(Map<String, Object> props) {
super(props);
}
}
then to use this default constructor, we simply do:
public class StaticInitDemo {
public static void main(String[] args) {
// create a translucent, yellow square...
Shape defaultSquare = new SquareShapeImpl();
// etc...
}
}
If you can use a String representation of your data this is an option too in Java 8:
static Map<Integer, String> MAP = Stream.of(
"1=one",
"2=two"
).collect(Collectors.toMap(k -> Integer.parseInt(k.split("=")[0]), v -> v.split("=")[1]));
One advantage to the second method is that you can wrap it with Collections.unmodifiableMap()
to guarantee that nothing is going to update the collection later:
private static final Map<Integer, String> CONSTANT_MAP =
Collections.unmodifiableMap(new HashMap<Integer, String>() {{
put(1, "one");
put(2, "two");
}});
// later on...
CONSTANT_MAP.put(3, "three"); // going to throw an exception!
I could strongly suggest the "double brace initialization" style over static block style.
Someone may comment that they don't like anonymous class, overhead, performance, etc.
But that I more consider is the code readability and maintainability. In this point of view, I stand a double brace is a better code style rather then static method.
In addition, it you aware the GC of the anonymous class, you can always convert it to a normal HashMap by using new HashMap(Map map)
.
You can do this until you faced another problem. If you do, you should use complete another coding style (e.g. no static, factory class) for it.
Java 5 provides this more compact syntax:
static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
put("Up", "Down");
put("Charm", "Strange");
put("Top", "Bottom");
}};
JEP 269 provides some convenience factory methods for Collections API. This factory methods are not in current Java version, which is 8, but are planned for Java 9 release.
For Map
there are two factory methods: of
and ofEntries
. Using of
, you can pass alternating key/value pairs. For example, in order to create a Map
like {age: 27, major: cs}
:
Map<String, Object> info = Map.of("age", 27, "major", "cs");
Currently there are ten overloaded versions for of
, so you can create a map containing ten key/value pairs. If you don't like this limitation or alternating key/values, you can use ofEntries
:
Map<String, Object> info = Map.ofEntries(
Map.entry("age", 27),
Map.entry("major", "cs")
);
Both of
and ofEntries
will return an immutable Map
, so you can't change their elements after construction. You can try out these features using JDK 9 Early Access.
If you want unmodifiable map, finally java 9 added a cool factory method of
to Map
interface. Similar method is added to Set, List as well.
Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
In Java 8, procedural approach can also be wrapped in Supplier
:
Map<String,String> m = ((Supplier<Map<String,String>>)(() -> {
Map<String,String> result = new HashMap<>();
result.put("foo","hoo");
...
return result;
)).get();
It's only hypothetical way but can come handy if you really need one-liner.
I have not seen the approach I use (and have grown to like) posted in any answers, so here it is:
I don't like using static initializers because they are clunky, and I don't like anonymous classes because it is creating a new class for each instance.
instead, I prefer initialization that looks like this:
map(
entry("keyA", "val1"),
entry("keyB", "val2"),
entry("keyC", "val3")
);
unfortunately, these methods are not part of the standard Java library, so you will need to create (or use) a utility library that defines the following methods:
public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)
public static <K,V> Map.Entry<K,V> entry(K key, V val)
(you can use 'import static' to avoid needing to prefix the method's name)
I found it useful to provide similar static methods for the other collections (list, set, sortedSet, sortedMap, etc.)
Its not quite as nice as json object initialization, but it's a step in that direction, as far as readability is concerned.
public class Test {
private static final Map<Integer, String> myMap;
static {
Map<Integer, String> aMap = ....;
aMap.put(1, "one");
aMap.put(2, "two");
myMap = Collections.unmodifiableMap(aMap);
}
}
If we declare more than one constant then that code will be written in static block and that is hard to maintain in future. So it is better to use anonymous class.
public class Test {
public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
{
put(1, "one");
put(2, "two");
}
});
}
And it is suggested to used unmodifiableMap for constants other wise it can't be treated as constant.
I've done something a bit different. Not the best, but it works for me. Maybe it could be "genericized".
private static final Object[][] ENTRIES =
{
{new Integer(1), "one"},
{new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);
private static Map newMap(Object[][] entries)
{
Map map = new HashMap();
for (int x = 0; x < entries.length; x++)
{
Object[] entry = entries[x];
map.put(entry[0], entry[1]);
}
return map;
}
I would use:
public class Test {
private static final Map<Integer, String> MY_MAP = createMap();
private static Map<Integer, String> createMap() {
Map<Integer, String> result = new HashMap<>();
result.put(1, "one");
result.put(2, "two");
return Collections.unmodifiableMap(result);
}
}
Because Java does not support map literals, map instances must always be explicitly instantiated and populated.
Fortunately, it is possible to approximate the behavior of map literals in Java using factory methods.
For example:
public class LiteralMapFactory {
// Creates a map from a list of entries
@SafeVarargs
public static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {
LinkedHashMap<K, V> map = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
// Creates a map entry
public static <K, V> Map.Entry<K, V> entry(K key, V value) {
return new AbstractMap.SimpleEntry<>(key, value);
}
public static void main(String[] args) {
System.out.println(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));
}
}
Output:
{a=1, b=2, c=3}
It is a lot more convenient than creating and populating the map an element at a time.
I would use:
public class Test {
private static final Map<Integer, String> MY_MAP = createMap();
private static Map<Integer, String> createMap() {
Map<Integer, String> result = new HashMap<>();
result.put(1, "one");
result.put(2, "two");
return Collections.unmodifiableMap(result);
}
}
Even with Guava's nice ImmutableMap class, sometimes I'd like to build a mutable map fluently. Finding myself wanting to avoid static blocks & the anonymous subtype thing, when Java 8 came along I wrote a tiny library to help called Fluent.
// simple usage, assuming someMap is a Map<String, String> already declared
Map<String, String> example = new Fluent.HashMap<String, String>()
.append("key1", "val1")
.append("key2", "val2")
.appendAll(someMap);
With Java 8 interface defaulting I could implement the Fluent.Map methods for all standard Java Map implementations (ie HashMap, ConcurrentSkipListMap, ... etc) without tedious repetition.
Unmodifiable maps are simple too.
Map<String, Integer> immutable = new Fluent.LinkedHashMap<String, Integer>()
.append("one", 1)
.append("two", 2)
.append("three", 3)
.unmodifiable();
See https://github.com/alexheretic/fluent for source, documentation and examples.
Now that Java 8 is out, this question warrants revisiting. I took a stab at it -- looks like maybe you can exploit lambda expression syntax to get a pretty nice and concise (but type-safe) map literal syntax that looks like this:
Map<String,Object> myMap = hashMap(
bob -> 5,
TheGimp -> 8,
incredibleKoolAid -> "James Taylor",
heyArnold -> new Date()
);
Map<String,Integer> typesafeMap = treeMap(
a -> 5,
bee -> 8,
sea -> 13
deep -> 21
);
Untested sample code at https://gist.github.com/galdosd/10823529 Would be curious about the opinions of others on this (it's mildly evil...)
Your second approach (Double Brace initialization) is thought to be an anti pattern, so I would go for the first approach.
Another easy way to initialise a static Map is by using this utility function:
public static <K, V> Map<K, V> mapOf(Object... keyValues) {
Map<K, V> map = new HashMap<>(keyValues.length / 2);
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 = mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = mapOf("key1", "value1", "key2", "value2");
Note: in Java 9
you can use Map.of
I like the anonymous class syntax; it's just less code. However, one major con I have found is that you won't be able to serialize that object via remoting. You will get an exception about not being able to find the anonymous class on the remote side.
public class Test {
private static final Map<Integer, String> myMap;
static {
Map<Integer, String> aMap = ....;
aMap.put(1, "one");
aMap.put(2, "two");
myMap = Collections.unmodifiableMap(aMap);
}
}
If we declare more than one constant then that code will be written in static block and that is hard to maintain in future. So it is better to use anonymous class.
public class Test {
public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
{
put(1, "one");
put(2, "two");
}
});
}
And it is suggested to used unmodifiableMap for constants other wise it can't be treated as constant.
If you want something terse and relatively safe, you can just shift compile-time type checking to run-time:
static final Map<String, Integer> map = MapUtils.unmodifiableMap(
String.class, Integer.class,
"cat", 4,
"dog", 2,
"frog", 17
);
This implementation should catch any errors:
import java.util.HashMap;
public abstract class MapUtils
{
private MapUtils() { }
public static <K, V> HashMap<K, V> unmodifiableMap(
Class<? extends K> keyClazz,
Class<? extends V> valClazz,
Object...keyValues)
{
return Collections.<K, V>unmodifiableMap(makeMap(
keyClazz,
valClazz,
keyValues));
}
public static <K, V> HashMap<K, V> makeMap(
Class<? extends K> keyClazz,
Class<? extends V> valClazz,
Object...keyValues)
{
if (keyValues.length % 2 != 0)
{
throw new IllegalArgumentException(
"'keyValues' was formatted incorrectly! "
+ "(Expected an even length, but found '" + keyValues.length + "')");
}
HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);
for (int i = 0; i < keyValues.length;)
{
K key = cast(keyClazz, keyValues[i], i);
++i;
V val = cast(valClazz, keyValues[i], i);
++i;
result.put(key, val);
}
return result;
}
private static <T> T cast(Class<? extends T> clazz, Object object, int i)
{
try
{
return clazz.cast(object);
}
catch (ClassCastException e)
{
String objectName = (i % 2 == 0) ? "Key" : "Value";
String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
}
}
}
Map.of
in Java 9+private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");
See JEP 269 for details. JDK 9 reached general availability in September 2017.
I've done something a bit different. Not the best, but it works for me. Maybe it could be "genericized".
private static final Object[][] ENTRIES =
{
{new Integer(1), "one"},
{new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);
private static Map newMap(Object[][] entries)
{
Map map = new HashMap();
for (int x = 0; x < entries.length; x++)
{
Object[] entry = entries[x];
map.put(entry[0], entry[1]);
}
return map;
}
We can use Map.ofEntries
, calling Map.entry( k , v )
to create each entry.
import static java.util.Map.entry;
private static final Map<Integer,String> map = Map.ofEntries(
entry(1, "one"),
entry(2, "two"),
entry(3, "three"),
entry(4, "four"),
entry(5, "five"),
entry(6, "six"),
entry(7, "seven"),
entry(8, "eight"),
entry(9, "nine"),
entry(10, "ten"));
We can also use Map.of
as suggested by Tagir in his answer here but we cannot have more than 10 entries using Map.of
.
We can create a Stream of map entries. We already have two implementations of Entry
in java.util.AbstractMap
which are SimpleEntry and SimpleImmutableEntry. For this example we can make use of former as:
import java.util.AbstractMap.*;
private static final Map<Integer, String> myMap = Stream.of(
new SimpleEntry<>(1, "one"),
new SimpleEntry<>(2, "two"),
new SimpleEntry<>(3, "three"),
new SimpleEntry<>(4, "four"),
new SimpleEntry<>(5, "five"),
new SimpleEntry<>(6, "six"),
new SimpleEntry<>(7, "seven"),
new SimpleEntry<>(8, "eight"),
new SimpleEntry<>(9, "nine"),
new SimpleEntry<>(10, "ten"))
.collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));
Here's a Java 8 one-line static map initializer:
private static final Map<String, String> EXTENSION_TO_MIMETYPE =
Arrays.stream(new String[][] {
{ "txt", "text/plain" },
{ "html", "text/html" },
{ "js", "application/javascript" },
{ "css", "text/css" },
{ "xml", "application/xml" },
{ "png", "image/png" },
{ "gif", "image/gif" },
{ "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" },
{ "svg", "image/svg+xml" },
}).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));
Edit: to initialize a Map<Integer, String>
as in the question, you'd need something like this:
static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
{1, "one"},
{2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));
Edit(2): There is a better, mixed-type-capable version by i_am_zero that uses a stream of new SimpleEntry<>(k, v)
calls. Check out that answer: https://stackoverflow.com/a/37384773/3950982
If you can use a String representation of your data this is an option too in Java 8:
static Map<Integer, String> MAP = Stream.of(
"1=one",
"2=two"
).collect(Collectors.toMap(k -> Integer.parseInt(k.split("=")[0]), v -> v.split("=")[1]));
This one uses Apache commons-lang which will most likely be on your class path already:
Map<String, String> collect = Stream.of(
Pair.of("hello", "world"),
Pair.of("abc", "123"),
Pair.of("java", "eight")
).collect(Collectors.toMap(Pair::getKey, Pair::getValue));
I would never create an anonymous subclass in this situation. Static initializers work equally well, if you would like to make the map unmodifiable for example:
private static final Map<Integer, String> MY_MAP;
static
{
Map<Integer, String>tempMap = new HashMap<Integer, String>();
tempMap.put(1, "one");
tempMap.put(2, "two");
MY_MAP = Collections.unmodifiableMap(tempMap);
}
I prefer using a static initializer to avoid generating anonymous classes (which would have no further purpose), so I'll list tips initializing with a static initializer. All listed solutions / tips are type-safe.
Note: The question doesn't say anything about making the map unmodifiable, so I will leave that out, but know that it can easily be done with Collections.unmodifiableMap(map)
.
First tip
The 1st tip is that you can make a local reference to the map and you give it a SHORT name:
private static final Map<Integer, String> myMap = new HashMap<>();
static {
final Map<Integer, String> m = myMap; // Use short name!
m.put(1, "one"); // Here referencing the local variable which is also faster!
m.put(2, "two");
m.put(3, "three");
}
Second tip
The 2nd tip is that you can create a helper method to add entries; you can also make this helper method public if you want to:
private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
p(1, "one"); // Calling the helper method.
p(2, "two");
p(3, "three");
}
private static void p(Integer k, String v) {
myMap2.put(k, v);
}
The helper method here is not re-usable though because it can only add elements to myMap2
. To make it re-usable, we could make the map itself a parameter of the helper method, but then initialization code would not be any shorter.
Third tip
The 3rd tip is that you can create a re-usable builder-like helper class with the populating functionality. This is really a simple, 10-line helper class which is type-safe:
public class Test {
private static final Map<Integer, String> myMap3 = new HashMap<>();
static {
new B<>(myMap3) // Instantiating the helper class with our map
.p(1, "one")
.p(2, "two")
.p(3, "three");
}
}
class B<K, V> {
private final Map<K, V> m;
public B(Map<K, V> m) {
this.m = m;
}
public B<K, V> p(K k, V v) {
m.put(k, v);
return this; // Return this for chaining
}
}
I like the Guava way of initialising a static, immutable map:
static final Map<Integer, String> MY_MAP = ImmutableMap.of(
1, "one",
2, "two"
);
As you can see, it's very concise (because of the convenient factory methods in ImmutableMap
).
If you want the map to have more than 5 entries, you can no longer use ImmutableMap.of()
. Instead, try ImmutableMap.builder()
along these lines:
static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
.put(1, "one")
.put(2, "two")
// ...
.put(15, "fifteen")
.build();
To learn more about the benefits of Guava's immutable collection utilities, see Immutable Collections Explained in Guava User Guide.
(A subset of) Guava used to be called Google Collections. If you aren't using this library in your Java project yet, I strongly recommend trying it out! Guava has quickly become one of the most popular and useful free 3rd party libs for Java, as fellow SO users agree. (If you are new to it, there are some excellent learning resources behind that link.)
Update (2015): As for Java 8, well, I would still use the Guava approach because it is way cleaner than anything else. If you don't want Guava dependency, consider a plain old init method. The hack with two-dimensional array and Stream API is pretty ugly if you ask me, and gets uglier if you need to create a Map whose keys and values are not the same type (like Map<Integer, String>
in the question).
As for future of Guava in general, with regards to Java 8, Louis Wasserman said this back in 2014, and [update] in 2016 it was announced that Guava 21 will require and properly support Java 8.
Update (2016): As Tagir Valeev points out, Java 9 will finally make this clean to do using nothing but pure JDK, by adding convenience factory methods for collections:
static final Map<Integer, String> MY_MAP = Map.of(
1, "one",
2, "two"
);
I could strongly suggest the "double brace initialization" style over static block style.
Someone may comment that they don't like anonymous class, overhead, performance, etc.
But that I more consider is the code readability and maintainability. In this point of view, I stand a double brace is a better code style rather then static method.
In addition, it you aware the GC of the anonymous class, you can always convert it to a normal HashMap by using new HashMap(Map map)
.
You can do this until you faced another problem. If you do, you should use complete another coding style (e.g. no static, factory class) for it.
One advantage to the second method is that you can wrap it with Collections.unmodifiableMap()
to guarantee that nothing is going to update the collection later:
private static final Map<Integer, String> CONSTANT_MAP =
Collections.unmodifiableMap(new HashMap<Integer, String>() {{
put(1, "one");
put(2, "two");
}});
// later on...
CONSTANT_MAP.put(3, "three"); // going to throw an exception!
I like the anonymous class syntax; it's just less code. However, one major con I have found is that you won't be able to serialize that object via remoting. You will get an exception about not being able to find the anonymous class on the remote side.
Java 5 provides this more compact syntax:
static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
put("Up", "Down");
put("Charm", "Strange");
put("Top", "Bottom");
}};
I like the anonymous class syntax; it's just less code. However, one major con I have found is that you won't be able to serialize that object via remoting. You will get an exception about not being able to find the anonymous class on the remote side.
Your second approach (Double Brace initialization) is thought to be an anti pattern, so I would go for the first approach.
Another easy way to initialise a static Map is by using this utility function:
public static <K, V> Map<K, V> mapOf(Object... keyValues) {
Map<K, V> map = new HashMap<>(keyValues.length / 2);
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 = mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = mapOf("key1", "value1", "key2", "value2");
Note: in Java 9
you can use Map.of
The anonymous class you're creating works well. However you should be aware that this is an inner class and as such, it'll contain a reference to the surrounding class instance. So you'll find you can't do certain things with it (using XStream for one). You'll get some very strange errors.
Having said that, so long as you're aware then this approach is fine. I use it most of the time for initialising all sorts of collections in a concise fashion.
EDIT: Pointed out correctly in the comments that this is a static class. Obviously I didn't read this closely enough. However my comments do still apply to anonymous inner classes.
Note: This answer actually belongs to question How to directly initialize a HashMap (in a literal way)? but since that's marked as duplicate of this one...
Prior to Java 9 with its Map.of() (which is also limited to 10 mappings) you can extend a Map
implementation of your choice, e.g.:
public class InitHashMap<K, V> extends HashMap<K, V>
re-implement HashMap
's constructors:
public InitHashMap() {
super();
}
public InitHashMap( int initialCapacity, float loadFactor ) {
super( initialCapacity, loadFactor );
}
public InitHashMap( int initialCapacity ) {
super( initialCapacity );
}
public InitHashMap( Map<? extends K, ? extends V> map ) {
super( map );
}
and add an additional constructor that's inspired by Aerthel's answer but is generic by using Object...
and <K, V>
types:
public InitHashMap( final Object... keyValuePairs ) {
if ( keyValuePairs.length >>> 1 != 0 )
throw new IllegalArgumentException( "Uneven number of arguments." );
K key = null;
int i = -1;
for ( final Object keyOrValue : keyValuePairs )
switch ( ++i >>> 1 ) {
case 0: // key
if ( keyOrValue == null )
throw new IllegalArgumentException( "Key[" + (i >>> 1) + "] is <null>." );
key = (K) keyOrValue;
continue;
case 1: // value
put( key, (V) keyOrValue );
}
}
public static void main( final String[] args ) {
final Map<Integer, String> map = new InitHashMap<>( 1, "First", 2, "Second", 3, "Third" );
System.out.println( map );
}
{1=First, 2=Second, 3=Third}
You also can extend the Map
interface likewise:
public interface InitMap<K, V> extends Map<K, V> {
static <K, V> Map<K, V> of( final Object... keyValuePairs ) {
if ( keyValuePairs.length >>> 1 != 0 )
throw new IllegalArgumentException( "Uneven number of arguments." );
final Map<K, V> map = new HashMap<>( keyValuePairs.length >>> 1, .75f );
K key = null;
int i = -1;
for ( final Object keyOrValue : keyValuePairs )
switch ( ++i >>> 1 ) {
case 0: // key
if ( keyOrValue == null )
throw new IllegalArgumentException( "Key[" + (i >>> 1) + "] is <null>." );
key = (K) keyOrValue;
continue;
case 1: // value
map.put( key, (V) keyOrValue );
}
return map;
}
}
public static void main( final String[] args ) {
System.out.println( InitMap.of( 1, "First", 2, "Second", 3, "Third" ) );
}
{1=First, 2=Second, 3=Third}
Here is the code by AbacusUtil
Map<Integer, String> map = N.asMap(1, "one", 2, "two");
// Or for Immutable map
ImmutableMap<Integer, String> = ImmutableMap.of(1, "one", 2, "two");
Declaration: I'm the developer of AbacusUtil.
Even with Guava's nice ImmutableMap class, sometimes I'd like to build a mutable map fluently. Finding myself wanting to avoid static blocks & the anonymous subtype thing, when Java 8 came along I wrote a tiny library to help called Fluent.
// simple usage, assuming someMap is a Map<String, String> already declared
Map<String, String> example = new Fluent.HashMap<String, String>()
.append("key1", "val1")
.append("key2", "val2")
.appendAll(someMap);
With Java 8 interface defaulting I could implement the Fluent.Map methods for all standard Java Map implementations (ie HashMap, ConcurrentSkipListMap, ... etc) without tedious repetition.
Unmodifiable maps are simple too.
Map<String, Integer> immutable = new Fluent.LinkedHashMap<String, Integer>()
.append("one", 1)
.append("two", 2)
.append("three", 3)
.unmodifiable();
See https://github.com/alexheretic/fluent for source, documentation and examples.
I would never create an anonymous subclass in this situation. Static initializers work equally well, if you would like to make the map unmodifiable for example:
private static final Map<Integer, String> MY_MAP;
static
{
Map<Integer, String>tempMap = new HashMap<Integer, String>();
tempMap.put(1, "one");
tempMap.put(2, "two");
MY_MAP = Collections.unmodifiableMap(tempMap);
}
As usual apache-commons has proper method MapUtils.putAll(Map, Object[]):
For example, to create a color map:
Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
});
Well... I like enums ;)
enum MyEnum {
ONE (1, "one"),
TWO (2, "two"),
THREE (3, "three");
int value;
String name;
MyEnum(int value, String name) {
this.value = value;
this.name = name;
}
static final Map<Integer, String> MAP = Stream.of( values() )
.collect( Collectors.toMap( e -> e.value, e -> e.name ) );
}
We can use Map.ofEntries
, calling Map.entry( k , v )
to create each entry.
import static java.util.Map.entry;
private static final Map<Integer,String> map = Map.ofEntries(
entry(1, "one"),
entry(2, "two"),
entry(3, "three"),
entry(4, "four"),
entry(5, "five"),
entry(6, "six"),
entry(7, "seven"),
entry(8, "eight"),
entry(9, "nine"),
entry(10, "ten"));
We can also use Map.of
as suggested by Tagir in his answer here but we cannot have more than 10 entries using Map.of
.
We can create a Stream of map entries. We already have two implementations of Entry
in java.util.AbstractMap
which are SimpleEntry and SimpleImmutableEntry. For this example we can make use of former as:
import java.util.AbstractMap.*;
private static final Map<Integer, String> myMap = Stream.of(
new SimpleEntry<>(1, "one"),
new SimpleEntry<>(2, "two"),
new SimpleEntry<>(3, "three"),
new SimpleEntry<>(4, "four"),
new SimpleEntry<>(5, "five"),
new SimpleEntry<>(6, "six"),
new SimpleEntry<>(7, "seven"),
new SimpleEntry<>(8, "eight"),
new SimpleEntry<>(9, "nine"),
new SimpleEntry<>(10, "ten"))
.collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));
Source: Stackoverflow.com