有没有这样初始化Java HashMap的方法?:

Map<String,String> test = 
    new HashMap<String, String>{"test":"test","test":"test"};

正确的语法是什么?我没有发现任何与此相关的信息。这可能吗?我正在寻找最短/最快的方法来将一些“最终/静态”值放在地图中,这些值永远不会改变,并且在创建地图时预先知道。


当前回答

执行此操作的简单方法:

public static Map<String, String> mapWithValues(String...values) {
    Map<String, String> map = new HashMap<String, String>();
    
    for (int x = 0; x < values.length; x = x+2) {
        map.put(values[x], values[x+1]);
    }
    
    return map;
}

其他回答

不幸的是,如果键和值的类型不同,则使用varargs不是很合理,因为您必须使用Object。。。并且完全失去类型安全性。如果你总是想创建一个Map<String,String>,当然可以创建一个toMap(String…args),但不是很漂亮,因为它很容易混淆键和值,奇数个参数是无效的。

您可以创建HashMap的子类,该子类具有可链接的方法,如

public class ChainableMap<K, V> extends HashMap<K, V> {
  public ChainableMap<K, V> set(K k, V v) {
    put(k, v);
    return this;
  }
}

并像使用新的ChainableMap<String,Object>().set(“a”,1).set“b”,“foo”)一样使用它

另一种方法是使用通用生成器模式:

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

  public MapBuilder<K, V> put(K k, V v) {
    mMap.put(k, v);
    return this;
  }

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

并像新的MapBuilder<String,Object>().put(“a”,1).pput(“b”,“foo”).build()那样使用它;

然而,我经常使用的解决方案使用varargs和Pair类:

public class Maps {
  public static <K, V> Map<K, V> of(Pair<K, V>... pairs) {
    Map<K, V> = new HashMap<>();

    for (Pair<K, V> pair : pairs) {
      map.put(pair.first, pair.second);
    }

    return map;
  }
}

Map<String,Object>Map=Maps.of(Pair.create(“a”,1),Pair.create(“b”,“foo”);

Pair.create()的冗长让我有点困扰,但这很好。如果您不介意静态导入,当然可以创建一个助手:

public <K, V> Pair<K, V> p(K k, V v) {
  return Pair.create(k, v);
}

Map<String,Object>Map=Map.of(p(“a”,1),p(“b”,“foo”);

(人们可以想象使用Map.Entry来代替Pair,但由于它是一个接口,所以它需要一个实现类和/或一个助手工厂方法。它也不是不可变的,并且包含对该任务不有用的其他逻辑。)

您可以通过两种简单的方式轻松地创建自己的Map.of(仅在Java9及更高版本中可用)方法

使用设定数量的参数

实例

public <K,V> Map<K,V> mapOf(K k1, V v1, K k2, V v2 /* perhaps more parameters */) {
    return new HashMap<K, V>() {{
      put(k1, v1);
      put(k2,  v2);
      // etc...
    }};
}

使用列表制作

您也可以使用列表来实现这一点,而不是为某一组参数创建许多方法。

实例

public <K, V> Map<K, V> mapOf(List<K> keys, List<V> values) {
   if(keys.size() != values.size()) {
        throw new IndexOutOfBoundsException("amount of keys and values is not equal");
    }

    return new HashMap<K, V>() {{
        IntStream.range(0, keys.size()).forEach(index -> put(keys.get(index), values.get(index)));
    }};
}

笔记不建议将其用于所有对象,因为每次使用时都会生成一个匿名类。

我找到了baeldung的一篇很棒的文章,其中列出了在不同Java版本中实现这一点的几种方法。

有几个有趣的方法很方便

对于任何Java版本

public static Map<String, String> articleMapOne;
static {
    articleMapOne = new HashMap<>();
    articleMapOne.put("ar01", "Intro to Map");
    articleMapOne.put("ar02", "Some article");
}

对于使用流的Java 8

Map<String, String> map = Stream.of(new String[][] {
  { "Hello", "World" }, 
  { "John", "Doe" }, 
}).collect(Collectors.toMap(data -> data[0], data -> data[1]));

of()似乎最普遍,也最不受限制。这里,它自动处理非对象输入值:

List<Map<String, Object> certs = new ArrayList<>(){{ add( Map.of(
    "TAG",          Obj1 // Object
    "TAGGED_ID",    1L //Long
    "DEGREE",       "PARENT" // String
    "DATE",         LocalDate.now() // LocalDate
));}};

注意,由静态Map.of(..)构造函数创建的映射不允许键和值都为空。

您可以在Java 8中使用Streams(这是Set的示例):

@Test
public void whenInitializeUnmodifiableSetWithDoubleBrace_containsElements() {
    Set<String> countries = Stream.of("India", "USSR", "USA")
      .collect(collectingAndThen(toSet(), Collections::unmodifiableSet));

    assertTrue(countries.contains("India"));
}

裁判:https://www.baeldung.com/java-double-brace-initialization