泛型:如何从数组填充地图?

Generics: How to populate a map from arrays?

我尝试编写一个实用程序方法,无论键和值的数据类型是什么,它都会从键和值数组填充映射。

  public static <K,V> Map<K,V> fillMap(Map<K,V> map, K[] keys, V[] values) {
    int l= keys.length;
    for (int i=0; i<l; i++)
      map.put(keys[i], values[i]);
    return map;
  }

然后我用

调用了方法
    HashMap<Integer, String> map= new HashMap<>();
    Integer[] keys= IntStream.range(0, 12).boxed().toArray(Integer[]::new);
    String[] values= new String[] {"Jan","Feb","Mar","Apr","Mai","Jun",
                   "Jul","Aug","Sep","Okt","Nov","Dez"};
    map= MyUtil.fillMap(map, keys, values);

并收到错误:
不兼容的类型:不存在类型变量 K、V 的实例,因此 Map 符合 HashMap
所有试图用 等到目前为止都失败了。 如何解决?

问题

在提供的代码中,我们声明:

HashMap<Integer, String> map = new HashMap<>();

public static <K,V> Map<K,V> fillMap(Map<K,V> map, K[] keys, V[] values)

因此,如果我们调用

map = MyUtil.fillMap(map, keys, values);

我们尝试将 Map<...>(由 MyUtil::fillMap 编辑的 return)分配给 HashMap<...>。这行不通,因为 Map 不是 HashMap


可能的解决方案

我想到了两种方法来解决这个问题:

  1. 要么改变 map,
  2. 的类型
  3. 或者使 MyUtil::fillMap 的 return 类型通用。

1。更改 map 的类型:

我们可以将 map 的类型从 HashMap<...> 更改为 Map<...>:

Map<Integer, String> map = new HashMap<>();
...
map = MyUtil.fillMap(map, keys, values);

Ideone demo

2。使 MyUtil::fillMap 的 return 类型通用:

通过添加一个额外的泛型参数,我们也可以使 return 类型的具体实现泛化:

public static void main(String[] args) {
  HashMap<Integer, String> map = new HashMap<>();
  final Integer[] keys = IntStream.range(0, 12).boxed().toArray(Integer[]::new);
  final String[] values = new String[] {"Jan", "Feb", "Mar", "Apr", "Mai", "Jun",
      "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};
  map = MyUtil.fillMap(map, keys, values);
  System.out.println(map);
}

public static <K, V, M extends Map<K, V>> M fillMap(M map, K[] keys, V[] values) {
  final int l = keys.length;
  for (int i = 0; i < l; i++) {
    map.put(keys[i], values[i]);
  }
  return map;
}

Ideone demo


奖励:return-value

的无状态构造

如果不需要传入用于该方法的映射的具体实现,我会提出第三个选项,即在方法内创建到 return 的映射:

public static <K, V> Map<K, V> fillMap(K[] keys, V[] values) {
  return IntStream.range(0, keys.length)
      .boxed()
      .collect(Collectors.toMap(
          index -> keys[index],
          index -> values[index]));
}

Ideone demo