使用Java自动在映射中创建缺失值的成语

3

我经常使用Map在循环中存储值,比如一组与同一类/组相关的对象的set/list,或者我想要递增的AtomicInteger。因此,我经常编写以下类型的代码(假设我不在我的Map中存储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 collections的DefaultedMap可以在缺少值时从工厂/模型对象中实时创建值;但是,为了避免编写2/3行代码的(相对较小的)麻烦,你会依赖于(另一个)外部库。
是否有更简单的解决方案(尤其是针对示例#2)?你们开发人员在这种情况下使用/推荐什么?还有其他提供这种“默认映射”的库吗?还是你们自己编写装饰映射?
3个回答

8
在Java 8中,Map接口新增了computeIfAbsent()方法:

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()));

3
Google的 guava-libraries也提供了这样的Map实现。但是我不会仅仅为了这个小好处而使用库。当你已经使用这样的库时,你可以考虑使用maps。但一般来说,这只是我的意见,我不喜欢为琐碎的事情使用库。
你问题中的例子对我来说看起来很好。我也在使用这个习惯用语。

1

对我来说,这看起来像是Java WS的MultivaluedMap的一部分。

同样也由Spring Framework实现。

因此,回答你的问题,没有默认的实现方式,你需要自己编写或者最好使用其中一个实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接