Lau*_*ire 3 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();
}
}
Run Code Online (Sandbox Code Playgroud)
我知道Apache Common集合DefaultedMap可以在工厂/模型对象丢失时动态创建一个值; 但你依靠(另一个)外部库只是为了避免编写2/3行代码的(相当小的)烦恼.
是否有更简单的解决方案(特别是例如#2)?在这种情况下,您的开发人员使用/推荐了什么?还有其他图书馆提供这种"默认地图"吗?你写自己的装饰地图吗?
在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);
Run Code Online (Sandbox Code Playgroud)
所以你可以按如下方式重写你的例子:
/* 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());
Run Code Online (Sandbox Code Playgroud)
另一个选择是使用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()));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1417 次 |
| 最近记录: |