3

我经常使用映射将值存储在循环中,例如属于同一类/组的对象集/列表,或者我想要递增的 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)?在这种情况下,您的开发人员同事使用/推荐什么?是否有其他库提供这种“默认地图”?你自己写装饰地图吗?

4

3 回答 3

8

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

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

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

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

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()));
于 2015-07-07T18:06:14.997 回答
3

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

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

于 2013-03-21T15:23:33.680 回答
1

在我看来,它看起来像是作为 Java WS 一部分的 MultivaluedMap

和Spring Framework实现的一样

因此,要回答您的问题,对此没有默认实现,您必须自行推出或更好地使用其中一种实现。

于 2013-03-21T15:26:23.677 回答