Java ConcurrentMap.compute用作删除
使用Java8,我在Java ConcurrentMap.compute用作删除,java,collections,java-8,java.util.concurrent,concurrenthashmap,Java,Collections,Java 8,Java.util.concurrent,Concurrenthashmap,使用Java8,我在Java.util.concurrent.ConcurrentMap接口上实现了一个包装器,特别是remove(objectkey)方法。因为我需要在删除过程中进行更多检查,所以我需要使用 compute(K键,双功能查看ConcurrentMap.compute的默认实现似乎您可以安全地使用未经检查的强制转换,假设您的remappingFunction可以处理对象而不是K类型并返回null public V remove(Object key) { @Suppres
Java.util.concurrent.ConcurrentMap
接口上实现了一个包装器,特别是remove(objectkey)
方法。因为我需要在删除过程中进行更多检查,所以我需要使用
compute(K键,双功能查看ConcurrentMap.compute的默认实现似乎您可以安全地使用未经检查的强制转换,假设您的remappingFunction
可以处理对象
而不是K
类型并返回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
。在这种情况下包含密钥(key)
将被调用,它也接受任何对象,并将为无效对象返回false
,而compute
将返回null
请注意,的行为有很好的文档记录(甚至提供了等效的代码),因此这种实现将来不太可能中断。请查看是否可以使用Map的forEach方法并将其放入forEach中
map.forEach((k, v) ->
System.out.println(k + "=" + v));
我想到的第一个想法是使用containsKey
预先检查map是否可以处理特定的键对象。如果此方法返回true
,map可以处理它,因此对K
进行未选中的强制转换就可以了
但是
ConcurrentMap<String,Integer> map=new ConcurrentSkipListMap<>();
map.put("foo", 42);
map.containsKey(0);
但是,除了线性搜索的性能外,理论上,如果在遍历过程中同时插入同一个密钥,则可能会多次删除密钥
因此,原子安全和类型安全的唯一解决方案是求助于运行时类型令牌(即通常通过类文本初始化):
要自动删除映射,如果存在并且检查
成功,但不能使用它返回删除是否实际发生,因为compute…
方法对不存在的键和在这两种情况下删除的键没有区别,将返回null
“我甚至不能做运行时检查,比如if(key instanceof K)。。。",您可以,但您必须将类
存储为包装器实例中的类型令牌。您可以安全地强制转换,因为擦除会剥离类型信息,映射只使用键的对象
方法。这是一种丑陋但安全且可接受的做法。ConcurrentMap.compute
只是默认实现,优化了c集合很可能直接实现,而不调用get等。ClassCastException(我自己还没有测试过)是ConcurrentSkipListMap的一个bug,因为它不遵守其约定。如果key不是key类型的实例,则返回false通常会破坏约定,因为这不考虑类型,只需equals()
results.:“抛出:ClassCastException
-如果该键的类型不适合此映射()”ConcurrentMap
不会修改此合同。如果基于类型的预检查不能解决您的问题,则根本没有类型安全解决方案。当然,您可能会发现ClassCastException
…是的,在文档中没有发现此部分。谢谢,尽管所需的解决方案似乎不存在。
ConcurrentMap<String,Integer> map=new ConcurrentSkipListMap<>();
map.put("foo", 42);
map.containsKey(0);
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);