【问题标题】:Increment an Integer within a HashMap在 HashMap 中增加一个整数
【发布时间】:2010-11-25 13:08:22
【问题描述】:

我必须返回对象然后放入一个新对象吗?或者我可以直接增加吗?

Integer temp = myMap.get(key);
temp++;
myMap.put(key, temp);

没有办法做到这一点(这不起作用):

myMap.get(key)++;

【问题讨论】:

    标签: java pointers reference hashmap


    【解决方案1】:

    这是完成这项工作的最短代码。

    myMap.put(key, myMap.get(key) + 1)
    

    我觉得不会太长。

    【讨论】:

    • 它应该如何工作? Put 方法有 2 个参数,键和新值。
    • +1 ,IMO 这应该是公认的答案:简单而简洁 - 不需要不可变的包装器(在非 MT 场景中放置原子构造是令人困惑的)。正如 Piotr 所观察到的,关键应该是第一个参数
    • 性能? 2 种搜索操作:一种使用 put(),一种使用 get()
    • @IgriZdes,由于 OP 在 Map 中存储不可变对象,因此无法避免重复搜索。唯一可以避免这种情况的解决方案是使用具有该解决方案所有优点和缺点的可变对象。
    • 请注意,如果没有为所有可能的键初始化值,则此解决方案会导致空指针异常。
    【解决方案2】:

    在 Java 8 中,Map 上有一些新方法,您可以使用 lambdas 来解决这个问题。第一种选择,compute

    a.compute(key, (k, v) -> v+1);
    

    请注意,这仅在为所有可能的键初始化散列时才有效。

    如果不能保证,您可以将上述代码更改为:

    a.compute(key, (k, v) -> v == null ? 1 : v + 1);
    

    或使用merge 方法(我更喜欢):

    a.merge(key, 1, (a, b) -> a + b);
    

    也许还有更多我不知道的基于 lambda 的方法。

    【讨论】:

    • 这是 java8 的最佳答案
    • FWIW 如果使用 Java 11,您可以使用 lambda 函数 a.merge(key, 1, Integer::sum);
    【解决方案3】:

    您可以使用可变整数,例如 AtomicInteger。

    Map<Key, AtomicInteger> myMap = new HashMap<Key, AtomicInteger>();
    myMap.get(key).incrementAndGet();
    

    或者您可以使用支持集合中的原语的 Trove4j。

    TObjectIntHashMap<Key> myMap;
    myMap.increment(key); 
    

    【讨论】:

    • 问题:当您说使用 incrementAndGet 时,您实际上是指:myMap.put(key, new AtomicLong(myMap.get(key).incrememtAndGet())); 对吗?是在map中插入新值还是incrementAndGet同时更新map中的值?
    • 地图包含一个引用,而不是对象本身。您不需要在映射中放回对可变对象的引用,因为您更改的是底层对象而不是引用。
    【解决方案4】:

    我必须返回对象然后放入一个新对象吗?

    只要您使用Integer 包装类就可以,因为它是不可变的。您可以改用可变包装类,即使是具有increment() 方法的包装类。但是,您将失去对值使用自动装箱和自动拆箱的能力。

    【讨论】:

      【解决方案5】:

      你不能直接增加它,因为它是immutable。您必须增加它并将新对象放回去。

      自动装箱也在这里干扰。事实上,发生的事情类似于:

      Integer i1 = getFromMap();
      i1 = Integer.valueOf(++ i1.intValue());
      

      所以这里你的引用指向一个新对象。您必须将该对象放回地图中,使用相同的键。

      【讨论】:

        【解决方案6】:

        由于Integer 是不可变的,是的,你必须这样做。 如果你真的想直接增加它,你必须编写自己的可变类。

        【讨论】:

        • 或者使用AtomicInteger
        【解决方案7】:

        如果您必须这样做两次以上,您更愿意创建一个小类,例如:

        public class MappedCounter {
        
            private Map<String, Integer> map = new HashMap<String, Integer>();
        
            public void addInt(String k, int v) {
                if (!map.containsKey(k))    map.put(k, v);
                else                map.put(k, map.get(k) + v);
            }
        
            public int getInt(String k) {
                return map.containsKey(k) ? map.get(k) : 0;
            }
        
            public Set<String> getKeys() {
                return map.keySet();
            }
        }
        

        【讨论】:

        • 这就是我所追求的。
        【解决方案8】:

        首先:注意拆箱:温度来自整数类型。但是操作 ++ 是针对 int 实现的。所以 temp 被拆箱以输入 int。这意味着如果 temp 为 null,您将在 NullPointerException 中运行。

        你必须像你在第一个代码块中描述的那样去做。

        【讨论】:

          【解决方案9】:

          我使用下面的代码,它可以工作,但一开始你需要定义一个BiFunction 来描述操作递增 1。

          public static Map<String, Integer> strInt = new HashMap<String, Integer>();
          
          public static void main(String[] args) {
              BiFunction<Integer, Integer, Integer> bi = (x,y) -> {
                  if(x == null)
                      return y;
                  return x+y;
              };
              strInt.put("abc", 0);
          
          
              strInt.merge("abc", 1, bi);
              strInt.merge("abc", 1, bi);
              strInt.merge("abc", 1, bi);
              strInt.merge("abcd", 1, bi);
          
              System.out.println(strInt.get("abc"));
              System.out.println(strInt.get("abcd"));
          }
          

          输出是

          3
          1
          

          【讨论】:

            【解决方案10】:

            为了完整起见,Java 8 中有一个 longAdder,与 AtomicInteger (http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/LongAdder.html) 相比,它带来了一些好处

            final Map<WhatEver, LongAdder> result = new HashMap<>();
            result.get(WhatEver).increment();
            

            【讨论】:

              【解决方案11】:

              这应该有效

                      // If the key you want to add does not exist then add it as a new key
                      // And make the value 1
                      if (map.get(key) == null) {
                          map.put(key, 1);
                      } else {
                          // If the key does exist then replace the key's value with it's
                          // Original value plus one
                          map.put(key, map.get(key) + 1);
                      }
              

              【讨论】:

              • 既然问题是“我可以直接在 HashMap 中增加一个整数吗”,我认为您的回答基本上是“否”。
              • 问题是 -> “在 HashMap 中增加一个整数”
              • 问题是“我必须返回对象然后再放入一个新对象吗?或者我可以直接递增吗?”。很抱歉您发现我的评论很粗鲁,但我认为如果答案不能解决问题,这非常无益。
              【解决方案12】:

              发现这是最好的方法,避免 NPE。

              Map<Integer, Integer> map = new HashMap<>();
              map.put(5, map.getOrDefault(5, 0) + 1);
              System.out.println(map.get(5));
              
              Output:
              1
              

              【讨论】:

                猜你喜欢
                • 2012-04-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-04-18
                • 2011-07-22
                • 1970-01-01
                相关资源
                最近更新 更多