Java 如何使用新的 computeIfAbsent 函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19278443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 15:39:27  来源:igfitidea点击:

How do I use the new computeIfAbsent function?

javadictionarylambdajava-8

提问by Benjamin H

I very much want to use Map.computeIfAbsentbut it has been too long since lambdas in undergrad.

我非常想使用Map.computeIfAbsent但是自从本科生 lambdas 以来已经太久了。

Almostdirectly from the docs: it gives an example of the old way to do things:

几乎直接来自文档:它给出了一个旧的做事方式的例子:

Map<String, Boolean> whoLetDogsOut = new ConcurrentHashMap<>();
String key = "snoop";
if (whoLetDogsOut.get(key) == null) {
  Boolean isLetOut = tryToLetOut(key);
  if (isLetOut != null)
    map.putIfAbsent(key, isLetOut);
}

And the new way:

以及新的方式:

map.computeIfAbsent(key, k -> new Value(f(k)));

But in their example, I think I'm not quite "getting it." How would I transform the code to use the new lambda way of expressing this?

但在他们的例子中,我想我还不太“明白”。我将如何转换代码以使用新的 lambda 表达方式?

采纳答案by Holger

Suppose you have the following code:

假设您有以下代码:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Test {
    public static void main(String[] s) {
        Map<String, Boolean> whoLetDogsOut = new ConcurrentHashMap<>();
        whoLetDogsOut.computeIfAbsent("snoop", k -> f(k));
        whoLetDogsOut.computeIfAbsent("snoop", k -> f(k));
    }
    static boolean f(String s) {
        System.out.println("creating a value for \""+s+'"');
        return s.isEmpty();
    }
}

Then you will see the message creating a value for "snoop"exactly once as on the second invocation of computeIfAbsentthere is already a value for that key. The kin the lambda expression k -> f(k)is just a placeolder (parameter) for the key which the map will pass to your lambda for computing the value. So in the example the key is passed to the function invocation.

然后您将看到该消息creating a value for "snoop"恰好一次,因为在第二次调用时computeIfAbsent已经存在该键的值。的k在λ表达式k -> f(k)仅仅是该地图将传递到您的拉姆达用于计算值的键一个placeolder(参数)。因此,在示例中,密钥被传递给函数调用。

Alternatively you could write: whoLetDogsOut.computeIfAbsent("snoop", k -> k.isEmpty());to achieve the same result without a helper method (but you won't see the debugging output then). And even simpler, as it is a simple delegation to an existing method you could write: whoLetDogsOut.computeIfAbsent("snoop", String::isEmpty);This delegation does not need any parameters to be written.

或者,您可以编写:whoLetDogsOut.computeIfAbsent("snoop", k -> k.isEmpty());在没有帮助方法的情况下实现相同的结果(但您将看不到调试输出)。甚至更简单,因为它是您可以编写的现有方法的简单委托:whoLetDogsOut.computeIfAbsent("snoop", String::isEmpty);此委托不需要编写任何参数。

To be closer to the example in your question, you could write it as whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key));(it doesn't matter whether you name the parameter kor key). Or write it as whoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut);if tryToLetOutis staticor whoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);if tryToLetOutis an instance method.

为了更接近问题中的示例,您可以将其写为whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key));(无论您命名参数k还是key)。或者把它写成whoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut);if tryToLetOutisstatic或者whoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);iftryToLetOut是一个实例方法。

回答by Edwin Dalorzo

Recently I was playing with this method too. I wrote a memoized algorithm to calcualte Fibonacci numbers which could serve as another illustration on how to use the method.

最近我也在玩这个方法。我写了一个记忆算法来计算斐波那契数,它可以作为如何使用该方法的另一个说明。

We can start by defining a map and putting the values in it for the base cases, namely, fibonnaci(0)and fibonacci(1):

我们可以通过定义地图,并把该值在它的基础的情况下启动,即,fibonnaci(0)fibonacci(1)

private static Map<Integer,Long> memo = new HashMap<>();
static {
   memo.put(0,0L); //fibonacci(0)
   memo.put(1,1L); //fibonacci(1)
}

And for the inductive step all we have to do is redefine our Fibonacci function as follows:

对于归纳步​​骤,我们所要做的就是重新定义我们的斐波那契函数,如下所示:

public static long fibonacci(int x) {
   return memo.computeIfAbsent(x, n -> fibonacci(n-2) + fibonacci(n-1));
}

As you can see, the method computeIfAbsentwill use the provided lambda expression to calculate the Fibonacci number when the number is not present in the map. This represents a significant improvement over the traditional, tree recursive algorithm.

如您所见,computeIfAbsent当数字不存在于地图中时,该方法将使用提供的 lambda 表达式来计算斐波那契数。这代表了对传统树递归算法的显着改进。

回答by hexabc

Another example. When building a complex map of maps, the computeIfAbsent() method is a replacement for map's get() method. Through chaining of computeIfAbsent() calls together, missing containers are constructed on-the-fly by provided lambda expressions:

另一个例子。在构建复杂的地图地图时,computeIfAbsent() 方法替代了地图的 get() 方法。通过将 computeIfAbsent() 调用链接在一起,缺失的容器可以通过提供的 lambda 表达式即时构建:

  // Stores regional movie ratings
  Map<String, Map<Integer, Set<String>>> regionalMovieRatings = new TreeMap<>();

  // This will throw NullPointerException!
  regionalMovieRatings.get("New York").get(5).add("Boyhood");

  // This will work
  regionalMovieRatings
    .computeIfAbsent("New York", region -> new TreeMap<>())
    .computeIfAbsent(5, rating -> new TreeSet<>())
    .add("Boyhood");

回答by nantitv

multi-map

多地图

This is really helpful if you want to create a multimapwithout resorting to the Google Guavalibrary for its implementation of MultiMap.

如果你想创建一个这是真正有用的多重映射而不诉诸谷歌番石榴库来实现的MultiMap

For example, suppose you want to store a list of students who enrolled for a particular subject.

例如,假设您要存储注册特定科目的学生列表。

The normal solution for this using JDK library is:

使用 JDK 库的正常解决方案是:

Map<String,List<String>> studentListSubjectWise = new TreeMap<>();
List<String>lis = studentListSubjectWise.get("a");
if(lis == null) {
    lis = new ArrayList<>();
}
lis.add("John");

//continue....

Since it have some boilerplate code, people tend to use Guava Mutltimap.

由于它有一些样板代码,人们倾向于使用 Guava Mutltimap

Using Map.computeIfAbsent, we can write in a single line without guava Multimap as follows.

使用Map.computeIfAbsent,我们可以在没有guava Multimap的情况下一行写成如下。

studentListSubjectWise.computeIfAbsent("a", (x -> new ArrayList<>())).add("John");

Stuart Marks & Brian Goetz did a good talk about this https://www.youtube.com/watch?v=9uTVXxJjuco

Stuart Marks 和 Brian Goetz 对此进行了很好的讨论 https://www.youtube.com/watch?v=9uTVXxJjuco