总览
Java 8库在地图上有一个新方法,computeIfAbsent。 这是一种非常有用的将地图变成与键关联的对象的缓存的方法。
但是,您可能没有考虑过一种组合。 如果您在内部调用computeIfAbsent会发生什么。
map.computeIfAbsent(Key.Hello, s -> {
map.computeIfAbsent(Key.Hello, t -> 1);
return 2;
});
enum Key {Hello}
尽管这在简单的情况下看起来很奇怪,但是在更复杂的代码中,您可能会偶然地这样做(就像我今天下午所做的那样)那么会发生什么呢? 好吧,这取决于您使用的集合。
HashMap: {Hello=2}
WeakHashMap: {Hello=2}
TreeMap: {Hello=2}
IdentityHashMap: {Hello=2}
EnumMap: {Hello=2}
Hashtable: {Hello=2, Hello=1}
LinkedHashMap: {Hello=1, Hello=2}
ConcurrentSkipListMap: {Hello=1}
ConcurrentHashMap:
注意: ConcurrentHashMap永不返回。 它的锁定似乎没有重入。
ConcurrentSkipListMap具有最合理的结果,保留第一个添加的值。 如果令人困惑,Hello = 2对于这种不确定的情况是合理的,因为它是第二个值而不是第一个值。 没有什么意义的是让唯一的不可变键出现两次。
不幸的是,ConcurrentHashMap死锁本身是不幸的,但至少不是那么微妙。
完整的代码。
public class A {
public static void main(String[] args) {
for (Map map : new Map[]{
new HashMap<>(),
new WeakHashMap<>(),
new TreeMap<>(),
new IdentityHashMap<>(),
new EnumMap<>(Key.class),
new Hashtable<>(),
new LinkedHashMap<>(),
new ConcurrentSkipListMap<>(),
new ConcurrentHashMap<>()
}) {
System.out.print(map.getClass().getSimpleName() + ": ");
map.computeIfAbsent(Key.Hello, s -> {
map.computeIfAbsent(Key.Hello, t -> 1);
return 2;
});
System.out.println(map);
}
}
enum Key {Hello}
}
方法compute()具有相似的结果
HashMap: {Hello=null2}
WeakHashMap: {Hello=null2}
TreeMap: {Hello=null2}
IdentityHashMap: {Hello=null2}
EnumMap: {Hello=null2}
Hashtable: {Hello=null2, Hello=1}
LinkedHashMap: {Hello=1, Hello=null2}
ConcurrentSkipListMap: {Hello=12}
ConcurrentHashMap:
public class A {
public static void main(String[] args) {
for (Map map : new Map[]{
new HashMap<>(),
new WeakHashMap<>(),
new TreeMap<>(),
new IdentityHashMap<>(),
new EnumMap<>(Key.class),
new Hashtable<>(),
new LinkedHashMap<>(),
new ConcurrentSkipListMap<>(),
new ConcurrentHashMap<>()
}) {
System.out.print(map.getClass().getSimpleName() + ": ");
map.compute(Key.Hello, (s, v) -> {
map.compute(Key.Hello, (s2, v2) -> "1");
return v + "2";
});
System.out.println(map);
}
}
enum Key {Hello}
}
结论
如果您要在lambda内部嵌套对地图的调用,则需要特别小心,或者完全避免这样做。 如果必须这样做,ConcurrentSkipListMap似乎表现最佳。
翻译自: https://www.javacodegeeks.com/2015/05/puzzler-nested-computeifabsent.html