难题:嵌套computeIfAbsent

总览

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值