Java HashMap在同一行执行put()和get()操作

huangapple go评论78阅读模式
英文:

Java HashMap performing put() and get() in same line

问题

我正在使用一个HashMap<String, Integer>来跟踪特定字符串的出现次数。我以单线程的方式执行以下操作:

   HashMap&lt;String, Integer&gt; count = new HashMap&lt;&gt;();
   // List&lt;String&gt; words = ...;
   for (String word : words) {
      if (!count.containsKey(word)) {
          count.put(word, 0);
      }
      count.put(word, count.get(word) + 1);
   }

对于相同的单词,是否有可能计数增加超过1,因为我同时在同一个键上执行put和get操作?也就是说,假设word = "hello"。最初,count.get(word) = 1。当我执行count.put(word, count.get(word) + 1)时,如果我再执行count.get(word),我得到的不是2,而是3。

英文:

I am using a HashMap<String, Integer> to keep track of count of an occurrence of a specific string. I am performing this operation in a single-thread manner in the following way:

   HashMap&lt;String, Integer&gt; count = new HashMap&lt;&gt;();
   // List&lt;String≥ words = ...;
   for (String word : words) {
      if (!count.containsKey(word)) {
          count.put(word, 0);
      }
      count.put(word, count.get(word) + 1);
   }

Is it possible, for the same word, the count increases by more than 1 because I am performing a put and get on the same key at the same time? i.e. Let's say the word = "hello". Initially, count.get(word) => 1. When I perform count.put(word, count.get(word) + 1), if I do count.get(word), instead of getting 2, I get 3.

答案1

得分: 2

Map具有computemerge方法,可实现对键的值的简短更新:

  1. compute
for (String word : words) {
    count.compute(word, (w, prev) -&gt; prev == null ? 1 : prev + 1);
}
  1. merge
for (String word : words) {
    count.merge(word, 1, (prev, one) -&gt; prev + one);
}

Lambda表达式(prev, one) -&gt; prev + one实际上是一个接受两个int参数并返回它们之和的函数,因此可以用方法引用Integer::sum替代:

for (String word : words) {
    count.merge(word, 1, Integer::sum);
}
英文:

Map has methods compute and merge that would allow to implement shorter updates of the values for the keys:

  1. compute
for (String word : words) {
    count.compute(word, (w, prev) -&gt; prev == null ? 1 : prev + 1);
}
  1. merge
for (String word : words) {
    count.merge(word, 1, (prev, one) -&gt; prev + one);
}

Lambda expression (prev, one) -&gt; prev + one is actually a function of two int arguments returning their sum, therefore it may be replaced with a method reference Integer::sum:

for (String word : words) {
    count.merge(word, 1, Integer::sum);
}

答案2

得分: 2

直接回答你的问题:count.put(word, count.get(word) + 1) 这个语句不可能使得值增加超过 1。尽管这两个方法调用在同一个语句中,但它们是按顺序执行的:get 首先执行,以找到传递给 put 的第二个参数。

你可以将缺失键的测试和初始化合并为一条语句:

count.putIfAbsent(word, 0);

这会在返回值之后方便地执行:

count.put(word, 1 + count.putIfAbsent(word, 0));

然而,也有一种已经将这两个操作结合起来的方法:

count.merge(word, 1, Integer::sum);
英文:

To answer your questions directly: no it is not possible for the statement count.put(word, count.get(word) + 1) to increment the value by more than 1. Although the two method calls are in the same statement they are performed sequentially: the get is performed first to find the second argument to pass to the put.

You can combine your missing key test and initialisation into a single statement:

count.putIfAbsent(word, 0);

This conveniently returns the value afterwards, allowing:

count.put(word, 1 + count.putIfAbsent(word, 0));

However there is also a method that already combines those two operations:

count.merge(word, 1, Integer::sum);

答案3

得分: 1

以下是翻译好的部分:

  • "It absolutely safe to do it in a single thread." -> "在单线程中执行这个操作是绝对安全的。"
  • "No, it's not possible that 'count increases by more than 1 because I am performing a put and get on the same key at the same time' because two operations never can happen at the same time with single-threaded execution." -> "不,'count 增加超过 1 是因为我同时在相同的键上执行 put 和 get 操作' 是不可能的,因为在单线程执行中不会同时发生两个操作。"
  • "Code count.put(word, count.get(word) + 1); will execute commands in following order:" -> "代码 count.put(word, count.get(word) + 1); 会按照以下顺序执行命令:"
  • "Integer value1 = count.get(word);" -> "Integer value1 = count.get(word);"
  • "int value2 = value1.intValue();" -> "int value2 = value1.intValue();"
  • "int value3 = value2 + 1;" -> "int value3 = value2 + 1;"
  • "Integer value4 = new Integer(value3);" -> "Integer value4 = new Integer(value3);"
  • "count.put(word, value4);" -> "count.put(word, value4);"
  • "By the way, your code will produce quite a lot of garbage and will be not very effective." -> "顺便说一下,你的代码会产生大量的垃圾并且不太有效率。"
  • "This way is more effective:" -> "这种方式更加有效:"
  • "private static class CounterHolder{" -> "private static class CounterHolder{"
  • "int value;" -> "int value;"
  • "Map<String, CounterHolder> count = new HashMap<>();" -> "Map<String, CounterHolder> count = new HashMap<>();"
  • "List<String> words = ..." -> "List words = ..."
  • "for (String word : words) {" -> "for (String word : words) {"
  • "CounterHolder holder;" -> "CounterHolder holder;"
  • "if (count.containsKey(word)) {" -> "if (count.containsKey(word)) {"
  • "holder = new CounterHolder();" -> "holder = new CounterHolder();"
  • "} else {" -> "} else {"
  • "holder = new CounterHolder();" -> "holder = new CounterHolder();"
  • "count.put(word, holder);" -> "count.put(word, holder);"
  • "++holder.value;" -> "++holder.value;"
英文:

It absolutely safe to do it in a single thread.
No, it's not possible that "count increases by more than 1 because I am performing a put and get on the same key at the same time" because two operations never can happen at the same time with single-threaded execution.

Code count.put(word, count.get(word) + 1); will execute commands in following order:

Integer value1 = count.get(word);
int value2 = value1.intValue();
int value3 = value2 + 1;
Integer value4 = new Integer(value3);
count.put(word, value4);

By the way, your code will produce quite a lot of garbage and will be not very effective.

This way is more effective:

private static class CounterHolder{
    int value;
}

Map&lt;String, CounterHolder&gt; count = new HashMap&lt;&gt;();
List&lt;String&gt; words = ...
for (String word : words) {
    CounterHolder holder;
    if (count.containsKey(word)) {
        holder = new CounterHolder();
    } else {
        holder = new CounterHolder();
        count.put(word, holder);
    }
    ++holder.value;
}

huangapple
  • 本文由 发表于 2020年10月24日 06:55:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/64508235.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定