builder for HashMap

Guava 为我们提供了很好的 Java 类型工厂方法,比如 Maps.newHashMap()

But are there also builders for java Maps?

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

你可使用:

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

虽然没那么经典可读,但很有效。

不完全是一个构建器,但使用初始化程序:

Map<String, String> map = new HashMap<String, String>() \{\{
put("a", "1");
put("b", "2");
}};

HashMaps 没有这样的东西,但是您可以使用一个构建器创建一个 ImmutableMap:

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

如果您需要一个可变的 map,您可以将其提供给 HashMap 构造函数。

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

HashMap是可变的; 不需要构建器。

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

一个简单的映射构建器写起来很简单:

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());
}
}
}

这与公认的答案相似,但在我看来更为清晰:

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

There are several variations of the above method, and they are great for making static, unchanging, immutable maps.

我以前也有过类似的要求。它与番石榴无关,但是您可以做类似的事情,以便能够使用流畅的构建程序清楚地构建 Map

创建一个扩展 Map 的基类。

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;
}
}

然后使用适合您需要的方法创建流畅的构建器:

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...


}

然后您可以这样实现它:

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

这是我一直想要的,特别是在设置测试装置时。最后,我决定自己编写一个简单流畅的构建器,它可以构建任何 Map 实现- 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;
}

这里有一个非常简单的..。

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);
}
}

那么

import static FluentHashMap.map;


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

参见 https://gist.github.com/culmat/a3bcc646fa4401641ac6eb01f3719065

Here's one I wrote

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);
}
}

你可以这样使用:

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();

由于 Java9Map接口包含:

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

这些工厂方法的局限性在于:

  • 不能将 null作为键和/或值(如果需要存储空值,请查看其他答案)
  • 制作 永恒不变地图

如果我们需要 易变的映射(如 HashMap) ,我们可以使用它的复制构造函数,并让它复制通过 Map.of(..)创建的映射的内容

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

使用 java 8:

这是 Java-9Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)的一种方法

public class MapUtil {
import static java.util.stream.Collectors.toMap;


import java.util.AbstractMap.SimpleEntry;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream;


private MapUtil() {}


@SafeVarargs
public static Map<String, Object> ofEntries(SimpleEntry<String, Object>... values) {
return Stream.of(values).collect(toMap(Entry::getKey, Entry::getValue));
}


public static SimpleEntry<String, Object> entry(String key, Object value) {
return new SimpleEntry<String, Object>(key, value);
}
}

使用方法:

import static your.package.name.MapUtil.*;


import java.util.Map;


Map<String, Object> map = ofEntries(
entry("id", 1),
entry("description", "xyz"),
entry("value", 1.05),
entry("enable", true)
);

你可以在 Eclipse 集合中使用流畅的 API:

Map<String, Integer> map = Maps.mutable.<String, Integer>empty()
.withKeyValue("a", 1)
.withKeyValue("b", 2);


Assert.assertEquals(Maps.mutable.with("a", 1, "b", 2), map);

Here's a 博客 with more detail and examples.

Note: I am a committer for Eclipse Collections.

番石榴里有 ImmutableMap.builder()