development

새로운 computeIfAbsent 함수를 어떻게 사용합니까?

big-blog 2020. 8. 29. 12:24
반응형

새로운 computeIfAbsent 함수를 어떻게 사용합니까?


나는 Map.computeIfAbsent 를 사용하고 싶지만 학부에서 람다 이후로 너무 오래되었습니다.

문서에서 거의 직접 : 작업을 수행하는 이전 방법의 예를 제공합니다.

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);
}

그리고 새로운 방법 :

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

그러나 그들의 예에서 나는 "그것을 이해"하고 있지 않다고 생각합니다. 이것을 표현하는 새로운 람다 방식을 사용하도록 코드를 어떻게 변환할까요?


다음 코드가 있다고 가정합니다.

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();
    }
}

그러면 해당 키에 대한 값이 이미있는 creating a value for "snoop"두 번째 호출 에서 메시지가 정확히 한 번만 표시됩니다 computeIfAbsent. k람다 표현은 k -> f(k)바로지도가 값을 계산하기 위해 람다로 전달됩니다 키에 대한 placeolder (매개 변수)입니다. 따라서 예제에서 키는 함수 호출로 전달됩니다.

또는 다음과 같이 작성할 수 whoLetDogsOut.computeIfAbsent("snoop", k -> k.isEmpty());있습니다. 도우미 메서드없이 동일한 결과를 얻을 있습니다 (하지만 디버깅 출력은 표시되지 않음). 또한 기존 메소드에 대한 간단한 위임이므로 더 간단합니다. whoLetDogsOut.computeIfAbsent("snoop", String::isEmpty);이 위임은 매개 변수를 작성할 필요가 없습니다.

으로 가까운 예에 질문에 있으려면, 당신은 그것을 쓸 수 whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key));(당신이 매개 변수의 이름을 여부를 중요하지 않습니다 k또는 key). 또는로 쓰는 whoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut);경우 tryToLetOut입니다 static또는 whoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);경우는 tryToLetOut인스턴스 방법이다.


최근에 저도이 방법을 가지고 놀았습니다. 나는 방법을 사용하는 방법에 대한 또 다른 예시가 될 수있는 피보나치 수를 계산하는 메모 알고리즘을 작성했습니다.

우리는지도를 정의하고 기본 경우에 그것의 값을 넣어 시작할 수 있습니다, 즉, 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)
}

귀납적 단계를 위해 우리가해야 할 일은 다음과 같이 피보나치 함수를 재정의하는 것입니다.

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

보시 computeIfAbsent다시피이 메서드 는 제공된 람다 식을 사용하여 숫자가지도에 없을 때 피보나치 수를 계산합니다. 이는 기존의 트리 재귀 알고리즘에 비해 상당한 개선을 나타냅니다.


다른 예시. 복잡한지도지도를 만들 때 computeIfAbsent () 메서드는지도의 get () 메서드를 대체합니다. computeIfAbsent () 호출을 함께 연결하면 누락 된 컨테이너가 제공된 람다 식에 의해 즉석에서 생성됩니다.

  // 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");

This is really helpful if you want to create a Multimap without using guava library (https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html)

For eg: If you want to store a list of students who enrolled for a particular subject. The normal solution for this using jdk library is

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 boiler plate code, people tend to use guava Mutltimap.

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

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

참고URL : https://stackoverflow.com/questions/19278443/how-do-i-use-the-new-computeifabsent-function

반응형