1

I wonder why there's no way to construct a map with values in a single expression. Or is it? I'd expect

new HashMap().add(key, value).add(key, value)...;

I can't find anything like that even in Commons Collections.

Did I miss some way in JDK or Commons?

3
  • Guava has that, see my answer Commented Jun 6, 2013 at 6:45
  • If you want a JDK only solution, you could write a simple class to do that, but it would be very limited. Commented Jun 6, 2013 at 6:50
  • @Djon it is actualy pretty easy to implement a builder, see my answer Commented Jun 6, 2013 at 7:13

4 Answers 4

4

Try this..

  Map<String, Integer> map = new HashMap<String, Integer>()
{{
     put("One", 1);
     put("Two", 2);
     put("Three", 3);
}};
Sign up to request clarification or add additional context in comments.

2 Comments

The above code makes use of block initialization. To make it clear, it creates an anonymous class whose only content is a block that will call several put
This can cause subtle problems due to the implicit reference to the outer class blog.p-y.wtf/avoid-java-double-brace-initialization
3

Guava has that with its ImmutableMap:

final Map<Foo, Bar> map = ImmutableMap.of(foo1, bar1, foo2, bar2, etc, etc);

Bonus: ImmutableMap's name is not a lie ;)

Note that there are 5 versions of the .of() method, so up to 5 key/value pairs. A more generic way is to use a builder:

final Map<Foo, Bar> map = ImmutableMap.<Foo, Bar>builder()
    .put(foo1, bar1)
    .put(foo2, bar2)
    .put(foo3, bar3)
    .put(etc, etc)
    .build();

Note, however: this map does not accept null keys or values.

Alternatively, here is a poor man's version of ImmutableMap. It uses a classical builder pattern. Note that it does not check for nulls:

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

    public MapBuilder<K, V> put(final K key, final V value)
    {
        map.put(key, value);
        return this;
    }

    public Map<K, V> build()
    {
        // Return a mutable copy, so that the builder can be reused
        return new HashMap<K, V>(map);
    }

    public Map<K, V> immutable()
    {
        // Return a copy wrapped into Collections.unmodifiableMap()
        return Collections.unmodifiableMap(build());
    }
}

Then you can use:

final Map<K, V> map = new MapBuilder<K, V>().put(...).put(...).immutable();

7 Comments

By pure habit. I make variables final where they can be, classes final when they are not meant to be inherited.
I put const whenever I can in C++, but I never thought of it in Java, strange world.
@Djon it also has nice side effects, such as allowing the use of a method parameter in an inner class which you return; if the method parameter were not final, this could not be possible. But in the end, it is all about coding style/habits/policy. I am final-happy ;)
Ad final: Restricting API has a nice result of having restricted API :) One can easily relax the API (e.g. remove final), but the other way is quite painful to the API consumers.
@OndraŽižka well, if you design a class so as not to allow it to be extended, final is there for you ;)
|
1

There is nothing in Commons Collections or in the JDK. But you could alternatively use Guava and the following code:

Map<String, String> mapInstance = ImmutableMap.<String, String> builder().put("key1", "value1").put("key2", "value2").build();

Comments

0
  • If your your keys and vales are of the same type then having such method:

    <K> Map<K, K> init(Map<K, K> map, K... args) {
        K k = null;
        for(K arg : args) {
            if(k != null) {
                map.put(k, arg);
                k = null;
            } else {
                k = arg;
            }
        }
        return map;
    }
    

    You can initialize your map with:

    init(new HashMap<String, String>(), "k1", "v1", "k2", "v2");
    
  • If your your keys and vales are of a different type then having such method:

    <K, V> Map<K, V> init(Map<K, V> map, List<K> keys, List<V> values) {
        for(int i = 0; i < keys.size(); i++) {
            map.put(keys.get(i), values.get(i));
        }
        return map;
    }
    

    You can initialize your map with:

    init(new HashMap<String, Integer>(), 
         Arrays.asList("k1", "k2"), 
         Arrays.asList(1, 2));
    

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.