3

Possible Duplicate:
builder for HashMap

Are there any utility class which allows to create a Map from a number of key-value pairs in a convenient and readable manner?

I thought that guava should have contain something but I couldn't find anything with necessary functionality.

What I want is something like this:

MapBuilder.newHashMap()
  .with("key1", 10)
  .with("key2", 20)
  .with("key3", 30)
  .build();

P.S. I also know about double-brace approach (new HashMap<>() {{ put(..); put(..); }}) but I don't find it either readable or convenient.

Community
  • 1
  • 1
Roman
  • 64,384
  • 92
  • 238
  • 332
  • @Roman about double-brace approach - this is anonymous class definition and you are calling put() in initialization block (second pair braces). I don't like this approach since it usually generates warning about missing serialVersionUID and you need @supressWarnings("serial"). – Sebastian Łaskawiec Jan 16 '12 at 11:31
  • 3
    see [Guava's ImmutableMap.Builder](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.Builder.html). For tiny maps like this one, also see the even more convenient [ImmutableMap.of](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html#method_summary). – Janus Troelsen Jan 11 '13 at 22:37
  • The above links are broken. New links: [ImmutableMap.builder()](https://github.com/google/guava/blob/064fac35d71231aba35062d1965983ecd36b6873/guava/src/com/google/common/collect/ImmutableMap.java#L184), [ImmutableMap.of()](https://github.com/google/guava/blob/064fac35d71231aba35062d1965983ecd36b6873/guava/src/com/google/common/collect/ImmutableMap.java#L114) – Jason Law Jun 04 '20 at 01:25

4 Answers4

6

What's wrong with

Map<String, Integer> map = new HashMap<>();
map.put("key1", 10);
map.put("key2", 20);
map.put("key3", 30);

That looks very readable to me, and I don't see what you gain from your MapBuilder. Anyway, such a MapBuilder wouldn't be hard to implement.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • agreed, very readable. agreed, easy to implement. (i hope i don't have bugs in my suggested implementation haha) – davogotland Jan 16 '12 at 11:29
5

Why not just roll your own?

public class MapBuilder<K,V> {

    private Map<K,V> map;

    public static <K,V> MapBuilder<K,V> newHashMap(){
            return new MapBuilder<K,V>(new HashMap<K,V>());
    }

    public MapBuilder(Map<K,V> map) {
        this.map = map;
    }

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

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

}
Robert
  • 8,406
  • 9
  • 38
  • 57
  • how will `K` and `V` be known to static method `newHashMap()`? – davogotland Jan 16 '12 at 11:32
  • is it the `` just after `static` that means that it will be fetched from the left side of an assignment operator? – davogotland Jan 16 '12 at 11:34
  • it is a generic method, as well as a generic class – Robert Jan 16 '12 at 11:34
  • i know it's a generic method. am i correct about where the types are derived from? – davogotland Jan 16 '12 at 11:37
  • yes, the types are bound when the method is called, and these types are then passed to the class. E.g, MapBuilder.newHashMap().with("Hello", "World") – Robert Jan 16 '12 at 11:41
  • 1
    The types are given when calling the method: MapBuilder.newHashMap(). If you declare a MapBuilder variable, it can be inferred from the type of the builder: MapBuilder b = MapBuilder.newHashMap(); – JB Nizet Jan 16 '12 at 11:41
2

How about creating your own AbstractMap with a put method that returns this?

public class MyMap<K, V> extends AbstractMap<K, V>{

    @Override
    public Set<java.util.Map.Entry<K, V>> entrySet() {
        // return set
        return null;
    }

    public MyMap<K, V> puts(K key, V value) {
        this.put(key, value);
        return this;
    };

}

Then use that method to chain pairs:

new MyMap<String, String>()
            .puts("foo", "bar")
            .puts("Hello", "World");
Jivings
  • 22,834
  • 6
  • 60
  • 101
0

from head, not tested:

import java.util.HashMap;

public class MapBuilder<K, E> {
    private HashMap<K, E>       m_hashMap;

    public static HashMap newHashMap(Class<K> keyClass, Class<E> elementClass) {
        return new MapBuilder<K, E>();
    }

    public MapBuilder() {
        m_hashMap = new HashMap<K, E>();
    }

    public MapBuilder with(K key, E element) {
        m_hashMap.put(key, element);

        return this;
    }

    public HashMap<K, E> build() {
        return m_hashMap;
    }
}

usage:

HashMap<String, Integer> myMap = MapBuilder.newHashMap(String.class, Integer.class)
    .with("key1", 10)
    .with("key2", 20)
    .with("key3", 30)
    .build();
davogotland
  • 2,718
  • 1
  • 15
  • 19
  • No need for the Class arguments. See Robert's answer for a better implementation. – JB Nizet Jan 16 '12 at 11:31
  • i saw it, and i asked about it. as i understand, that won't make it possible to create it without assigning it? not something one wants to do really often, but still :) – davogotland Jan 16 '12 at 11:35