使用Java在地图中自动创建缺失值的习惯用法

时间:2013-03-21 15:14:19

标签: java collections idioms

我经常使用map在循环中存储值,例如属于同一个类/组的对象的set / list,或者我想要递增的AtomicInteger。因此,我经常编写以下类型的代码(假设我不在地图中存储null):

/* Example #1 -- aggregation */
Map<K, Set<O>> map = new HashMap<K, Set<O>>();
for (O o : oList) {
    K k = o.getK();
    Set<O> oSet = map.get(k);
    if (oSet == null) {
        oSet = new HashSet<O>(o);
        map.put(k, oSet);
    } else {
        oSet.add(o);
    }
}

/* Example #2 -- counting */
Map<K, AtomicInteger> map = new HashMap<K, AtomicInteger>();
for (O o : oList) {
    K k = o.getK();
    AtomicInteger i = map.get(k);
    if (i == null) {
        i = new AtomicInteger(1);
        map.put(k, i);
    } else {
        i.increment();
    }
}

我知道Apache Common集合DefaultedMap,它可以在工厂/模型对象丢失时动态创建一个值;但你依靠(另一个)外部库只是为了避免编写2/3行代码的(相当小的)烦恼。

是否有更简单的解决方案(特别是例如#2)?在这种情况下,您的开发人员使用/推荐了什么?是否有其他图书馆提供这种&#34;默认地图&#34;?你写自己的装饰地图吗?

3 个答案:

答案 0 :(得分:7)

在Java 8中,方法computeIfAbsent()已添加到Map接口:

  

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

     

如果指定的键尚未与值关联(或映射为null),则尝试使用给定的映射函数计算其值,并将其输入此映射,除非为null。

根据documentation,最常见的用法是创建一个新对象作为初始映射值或实现多值映射。例如:

map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);

所以你可以按如下方式重写你的例子:

/* Example #1 -- aggregation */
Map<K, Set<O>> map = new HashMap<>();
oList.forEach(o -> map.computeIfAbsent(o.getK(), k -> new HashSet<>()).add(o));

/* Example #2 -- counting */
Map<K, AtomicInteger> map = new HashMap<>();
oList.forEach(o -> map.computeIfAbsent(o.getK(), k -> new AtomicInteger(0)).incrementAndGet());

另一种选择是将Stream API与Collectors.groupingBy一起使用:

/* Example #1 -- aggregation */
Map<K, Set<O>> map = oList.stream()
                          .collect(Collectors.groupingBy(O::getK, Collectors.toSet()));

/* Example #2 -- counting using a Long instead of an AtomicInteger */
Map<K, Long> map = oList.stream()
                        .map(O::getK)
                        .collect(Collectors.groupingBy(k -> k, Collectors.counting()));

答案 1 :(得分:3)

Google的guava-libraries也提供了这样的地图实施。 但我不会仅仅为了这么小的利益而使用图书馆。当您已经使用这样的库时,您可以考虑使用这些地图。但总的来说,这只是我的意见,我不喜欢将库用于琐碎的事情。

您的问题中的示例对我来说似乎很好。我也在用这个成语。

答案 2 :(得分:1)

对我来说,它看起来像MultivaluedMap作为Java WS的一部分。

Spring Framework

实施的相同

所以为了回答你的问题,没有默认的实现,你必须自己动手或更好地使用其中一个实现。