使用Java 8,我在java.util.concurrent.ConcurrentMap
接口上实现了一个包装器,特别是remove(Object key)
方法。由于我需要在删除期间进行更多检查,因此我需要使用
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
但是,问题在于:我必须接受Object
,但将其作为compute
传递给K
。使用泛型,我甚至无法像if (key instanceof K) ...
我理解为什么compute
的签名是这样选择的;如果它只是Object
,如果计算需要创建一个新条目,它就不能简单地使用密钥。但我不知道如何解决这个问题 - 有没有推荐的模式,但是如下所示使用多个调用?
for (;;) {
V v = map.get();
if (check(k, v)) {
if (map.remove(k, v)) return true;
} else return false;
}
由于
答案 0 :(得分:1)
查看ConcurrentMap.compute
的默认实现,似乎您可以安全地使用未经检查的强制转换,假设您的remappingFunction
可以处理Object
而不是K
类型并返回{ {1}}。所以你可以使用:
null
public V remove(Object key) {
@SuppressWarnings("unchecked")
V result = compute((K)key, (k, v) -> {
if(v == null) return null;
...
});
...
}
实现首先使用compute
(接受任何对象,因此它是安全的),并将结果传递给get(key)
。如果密钥的类型无效,则结果为remappingFunction
,因此您的null
也应返回remappingFunction
。在这种情况下,null
将被调用,它也会接受任何对象,并会返回containsKey(key)
作为无效对象,而false
将返回compute
。
请注意ConcurretMap.compute
的行为已有详细记录(即使提供了等效的代码),因此将来不太可能破坏此类实现。
答案 1 :(得分:1)
我想到的第一个想法是使用containsKey
预先检查地图是否可以处理特定的关键对象。如果此方法返回true
,则地图可以处理它,因此未经检查的强制转换为K
即可。
但是...
ConcurrentMap<String,Integer> map=new ConcurrentSkipListMap<>();
map.put("foo", 42);
map.containsKey(0);
已足以证明,尽管方法containsKey
具有Object
作为参数类型,但它不一定适用于任意参数类型 - 在这种情况下它会抛出{{1} }。
也就是说,使用ClassCastException
和get(Object)
的原始循环也无法保证正常工作。
如果没有其他类型的令牌,只有一种类型安全的方法:
remove(Object,Object)
但除了线性搜索的性能之外,如果在遍历期间同时插入相同的密钥,则理论上可能会多次删除密钥。
因此,原子和类型安全的唯一解决方案是求助于运行时类型令牌(即通常通过类文字初始化):
return map.entrySet().removeIf(e ->
Objects.equals(key, e.getKey()) && check(e.getKey(), e.getValue()));
请注意,您可以使用
之类的内容ConcurrentMap<K, V> map;
Class<K> keyType;
public boolean remove(Object key) {
if(!keyType.isInstance(key)) return false;
K k=keyType.cast(key);
for(;;) {
V v=map.get(k);
if(v==null || !check(k,v)) return false;
if(map.remove(k, v)) return true;
}
}
以原子方式删除映射(如果存在且if(keyType.isInstance(key))
map.computeIfPresent(keyType.cast(key), (k,v) -> check(k, v)? null: v);
成功,但您无法使用它来返回是否实际发生了删除,因为check
方法之间没有区别在两种情况下都会删除礼物和钥匙,compute…
将被退回。
答案 2 :(得分:0)
看看你是否可以使用Map的forEach方法并将其放入forEach
map.forEach((k, v) ->
System.out.println(k + "=" + v));