wake-up-neo.net

builder für HashMap

Guava bietet uns großartige Factory-Methoden für Java-Typen wie Maps.newHashMap().

Gibt es aber auch Builder für Java Maps?

HashMap<String,Integer> m = Maps.BuildHashMap.
    put("a",1).
    put("b",2).
    build();
95

Für HashMaps gibt es nichts dergleichen, aber Sie können eine ImmutableMap mit einem Builder erstellen:

final Map<String, Integer> m = ImmutableMap.<String, Integer>builder().
      put("a", 1).
      put("b", 2).
      build();

Und wenn Sie eine veränderbare Map benötigen, können Sie diese einfach dem HashMap-Konstruktor zuführen.

final Map<String, Integer> m = Maps.newHashMap(
    ImmutableMap.<String, Integer>builder().
        put("a", 1).
        put("b", 2).
        build());
150

Nicht gerade ein Builder, aber mit einem Initialisierer: 

Map<String, String> map = new HashMap<String, String>() {{
    put("a", "1");
    put("b", "2");
}};
42
Johan Sjöberg

Dies ist ähnlich der akzeptierten Antwort, aber meiner Meinung nach etwas sauberer:

ImmutableMap.of("key1", val1, "key2", val2, "key3", val3);

Es gibt mehrere Variationen der obigen Methode, und sie eignen sich hervorragend zum Erstellen statischer, unveränderlicher, unveränderlicher Karten.

34
Jake Toronto

Da Java 9 Map Interface enthält:

  • Map.of(k1,v1, k2,v2, ..)
  • Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ..).

Einschränkungen dieser Fabrikmethoden sind, dass sie:

  • kann nulls nicht als Schlüssel und/oder Werte speichern (wenn Sie Nullen speichern müssen, schauen Sie sich andere Antworten an)
  • produzieren unveränderliche Karten - wenn wir veränderbare Karten brauchen, können wir Konstruktor der ausgewählten veränderlichen Karte wie HashMap und Übergabe des Ergebnisses von Map.of(..) like

    Map<Integer, String> map = new HashMap<>( Map.of(1,"a", 2,"b", 3,"c") );
    
8
Pshemo

Ein einfacher Map Builder ist einfach zu schreiben:

public class Maps {

    public static <Q,W> MapWrapper<Q,W> map(Q q, W w) {
        return new MapWrapper<Q, W>(q, w);
    }

    public static final class MapWrapper<Q,W> {
        private final HashMap<Q,W> map;
        public MapWrapper(Q q, W w) {
            map = new HashMap<Q, W>();
            map.put(q, w);
        }
        public MapWrapper<Q,W> map(Q q, W w) {
            map.put(q, w);
            return this;
        }
        public Map<Q,W> getMap() {
            return map;
        }
    }

    public static void main(String[] args) {
        Map<String, Integer> map = Maps.map("one", 1).map("two", 2).map("three", 3).getMap();
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}
7
Agnes

Sie können verwenden:

HashMap<String,Integer> m = Maps.newHashMap(
    ImmutableMap.of("a",1,"b",2)
);

Es ist nicht so edel und lesbar, erledigt aber die Arbeit.

6

Hier ist eine sehr einfache ...

public class FluentHashMap<K, V> extends Java.util.HashMap<K, V> {
  public FluentHashMap<K, V> with(K key, V value) {
    put(key, value);
    return this;
  }

  public static <K, V> FluentHashMap<K, V> map(K key, V value) {
    return new FluentHashMap<K, V>().with(key, value);
  }
}

dann 

import static FluentHashMap.map;

HashMap<String, Integer> m = map("a", 1).with("b", 2);

Siehe https://Gist.github.com/culmat/a3bcc646fa4401641ac6eb01f3719065

3
culmat

HashMap ist veränderlich; Es ist kein Bauherr nötig.

Map<String, Integer> map = Maps.newHashMap();
map.put("a", 1);
map.put("b", 2);
3
ColinD

Hier ist einer, den ich geschrieben habe

import Java.util.Collections;
import Java.util.HashMap;
import Java.util.Map;
import Java.util.function.Supplier;

public class MapBuilder<K, V> {

    private final Map<K, V> map;

    /**
     * Create a HashMap builder
     */
    public MapBuilder() {
        map = new HashMap<>();
    }

    /**
     * Create a HashMap builder
     * @param initialCapacity
     */
    public MapBuilder(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    /**
     * Create a Map builder
     * @param mapFactory
     */
    public MapBuilder(Supplier<Map<K, V>> mapFactory) {
        map = mapFactory.get();
    }

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

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

    /**
     * Returns an unmodifiable Map. Strictly speaking, the Map is not immutable because any code with a reference to
     * the builder could mutate it.
     *
     * @return
     */
    public Map<K, V> buildUnmodifiable() {
        return Collections.unmodifiableMap(map);
    }
}

Du verwendest es so:

Map<String, Object> map = new MapBuilder<String, Object>(LinkedHashMap::new)
    .put("event_type", newEvent.getType())
    .put("app_package_name", newEvent.getPackageName())
    .put("activity", newEvent.getActivity())
    .build();
0
Dónal

Das wollte ich immer, vor allem beim Einrichten von Testvorrichtungen. Schließlich entschied ich mich, einen einfachen, fließenden Builder zu schreiben, der jede Map-Implementierung erstellen konnte. - https://Gist.github.com/samshu/b471f5a2925fa9d9b718795d8bbdfe42#file-mapbuilder-Java

    /**
     * @param mapClass Any {@link Map} implementation type. e.g., HashMap.class
     */
    public static <K, V> MapBuilder<K, V> builder(@SuppressWarnings("rawtypes") Class<? extends Map> mapClass)
            throws InstantiationException,
            IllegalAccessException {
        return new MapBuilder<K, V>(mapClass);
    }

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

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

Ich hatte vor einer Weile eine ähnliche Anforderung. Es hat nichts mit Guava zu tun, aber Sie können so etwas tun, um eine Map sauber mit einem fließenden Builder erstellen zu können.

Erstellen Sie eine Basisklasse, die Map erweitert.

public class FluentHashMap<K, V> extends LinkedHashMap<K, V> {
    private static final long serialVersionUID = 4857340227048063855L;

    public FluentHashMap() {}

    public FluentHashMap<K, V> delete(Object key) {
        this.remove(key);
        return this;
    }
}

Dann erstellen Sie den fließenden Builder mit Methoden, die Ihren Anforderungen entsprechen:

public class ValueMap extends FluentHashMap<String, Object> {
    private static final long serialVersionUID = 1L;

    public ValueMap() {}

    public ValueMap withValue(String key, String val) {
        super.put(key, val);
        return this;
    }

... Add withXYZ to suit...

}

Sie können es dann so implementieren:

ValueMap map = new ValueMap()
      .withValue("key 1", "value 1")
      .withValue("key 2", "value 2")
      .withValue("key 3", "value 3")
0
tarka