【问题标题】:Generic autovivify function for Maps地图的通用自动激活功能
【发布时间】:2015-11-20 07:15:07
【问题描述】:

如何使用泛型创建激活键?这段代码甚至无法编译:

/* populate the map with a new value if the key is not in the map */
private <K,V> boolean autoVivify(Map<K,V> map, K key)
{
  if (! map.containsKey(key))
  {
    map.put(key, new V());
    return false;
  }
  return true;
}

【问题讨论】:

  • 这似乎可以编译(未测试):(V)(map.getClass().getTypeParameters()[1].getClass()).newInstance()

标签: java generics dictionary autovivification


【解决方案1】:

您需要告诉方法如何创建值。

interface Producer<T> {

    T make();
}

private <K, V> boolean autoVivify(Map<K, V> map, K key, Producer<V> maker) {
    if (!map.containsKey(key)) {
        map.put(key, maker.make());
        return false;
    }
    return true;
}

或者 - 使用nullHashMap 可以包含null,尽管TreeMap 可能有困难。

private <K, V> boolean autoVivify(Map<K, V> map, K key) {
    if (!map.containsKey(key)) {
        map.put(key, null);
        return false;
    }
    return true;
}

【讨论】:

  • 其实TreeMap如果是用null-friendly比较器创建的,可以包含null。
  • @TagirValeev - 即使是为了价值?肯定会发生奇怪的事情,因为TreeMap 的几个方法被定义为如果找不到密钥则返回null
  • 啊,对不起。对于值,您甚至不需要比较器。 TreeMap 完美支持空值。
【解决方案2】:

如果V 有一个没有参数的构造函数,你可以使用反射来创建一个实例

private <K, V> boolean autoVivify(Map<K, V> map, K key, Class<V> clazz) throws Exception {
    if (!map.containsKey(key)) {
        map.put(key, clazz.getConstructor().newInstance());
        return false;
    }
    return true;
}

Map<Integer, String> map = new HashMap<>();
autoVivify(map, 3, String.class);

【讨论】:

    【解决方案3】:

    在 Java-8 中,提供 Supplier 并使用 computeIfAbsent 是合理的:

    private <K,V> boolean autoVivify(Map<K,V> map, K key, Supplier<V> supplier) {
        boolean[] result = {true};
        map.computeIfAbsent(key, k -> {
          result[0] = false;
          return supplier.get();
        });
        return result[0];
    }
    

    使用示例:

    Map<String, List<String>> map = new HashMap<>();
    autoVivify(map, "str", ArrayList::new);
    

    请注意,与 containsKey/put 不同,使用 computeIfAbsent 的解决方案对于并发映射是安全的:不会发生竞争条件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      • 2017-01-12
      • 1970-01-01
      • 2021-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多