example computeifpresent computeifabsent java dictionary lambda java-8

java - computeifpresent - ¿Cómo uso la nueva función computeIfAbsent?



computeifabsent example (5)

Esto es realmente útil si desea crear un Multimap sin usar la biblioteca guava ( https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html )

Por ejemplo: si desea almacenar una lista de estudiantes que se inscribieron para un tema en particular. La solución normal para esto es usar la biblioteca jdk

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

Dado que tiene un código de placa de caldera, las personas tienden a usar guayaba Mutltimap.

Usando Map.compute If One, podemos escribir en una sola línea sin guava Multimap de la siguiente manera.

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

Stuart Marks y Brian Goetz hicieron una buena charla sobre esto https://www.youtube.com/watch?v=9uTVXxJjuco

Tengo muchas ganas de usar Map.computeIfAbsent pero ha pasado demasiado tiempo desde lambdas en pregrado.

Casi directamente de los documentos: da un ejemplo de la forma antigua de hacer las cosas:

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

Y la nueva forma:

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

Pero en su ejemplo, creo que no estoy "entendiéndolo". ¿Cómo podría transformar el código para usar la nueva forma lambda de expresar esto?


No hay diferencia entre usar computeIfAbsent () y simple put () get ()
funciones de un mapa. En otras palabras, puede reescribir su función de esta manera

for (char ch : input){ Integer value; if(countMap.containsKey(ch)){ value = countMap.get(ch); value++; countMap.put(ch, value); } else{ value = 1; countMap.put(ch, value); } }


Otro ejemplo. Al construir un mapa complejo de mapas, el método computeIfAbsent () reemplaza el método get () del mapa. Mediante el encadenamiento de las llamadas a computeIfAbsent (), los contenedores faltantes se construyen sobre la marcha con expresiones lambda proporcionadas:

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


Recientemente también estaba jugando con este método. Escribí un algoritmo memorado para calcular los números de Fibonacci que podría servir como otra ilustración sobre cómo usar el método.

Podemos comenzar por definir un mapa y poner los valores en él para los casos base, es decir, fibonnaci(0) y fibonacci(1) :

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

Y para el paso inductivo, todo lo que tenemos que hacer es redefinir nuestra función de Fibonacci de la siguiente manera:

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

Como puede ver, el método computeIfAbsent usará la expresión lambda proporcionada para calcular el número de Fibonacci cuando el número no está presente en el mapa. Esto representa una mejora significativa sobre el algoritmo recursivo de árbol tradicional.


Supongamos que tiene el siguiente código:

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

Luego, verá el mensaje creating a value for "snoop" exactamente una vez como en la segunda invocación de computeIfAbsent ya existe un valor para esa clave. El k en la expresión lambda k -> f(k) es solo un placeolder (parámetro) para la clave que el mapa pasará a su lambda para calcular el valor. Entonces, en el ejemplo, la clave se pasa a la invocación de la función.

Alternativamente, podría escribir: whoLetDogsOut.computeIfAbsent("snoop", k -> k.isEmpty()); para lograr el mismo resultado sin un método de ayuda (pero no verá la salida de depuración). Y aún más simple, ya que es una simple delegación a un método existente que podría escribir: whoLetDogsOut.computeIfAbsent("snoop", String::isEmpty); Esta delegación no necesita ningún parámetro para ser escrito.

Para estar más cerca del ejemplo en su pregunta, puede escribirlo como whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key)); (No importa si nombra el parámetro k o la key ). O escríbalo como whoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut); si tryToLetOut es static o whoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut); si tryToLetOut es un método de instancia.