Tengo muchas ganas de usar Map.computeIfAbsent, pero ha pasado demasiado tiempo desde las lambdas en la licenciatura.
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 lo estoy "entendiendo" del todo. ¿Cómo transformaría el código para usar la nueva forma lambda de expresar esto?
java
dictionary
lambda
java-8
Benjamín H
fuente
fuente
Respuestas:
Suponga que tiene el siguiente código:
Luego verá el mensaje
creating a value for "snoop"
exactamente una vez, ya que en la segunda invocacióncomputeIfAbsent
ya existe un valor para esa clave. Enk
la expresión lambdak -> f(k)
es solo un marcador de posición (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 auxiliar (pero no verá la salida de depuración entonces). 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 de su pregunta, puede escribirlo como
whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key));
(no importa si nombra el parámetrok
okey
). O escribir comowhoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut);
sitryToLetOut
esstatic
owhoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);
sitryToLetOut
es un método de instancia.fuente
Recientemente también estuve jugando con este método. Escribí un algoritmo memorizado para calcular los números de Fibonacci que podría servir como otra ilustración sobre cómo usar el método.
Podemos comenzar definiendo un mapa y poniendo los valores en él para los casos base, a saber,
fibonnaci(0)
yfibonacci(1)
:Y para el paso inductivo, todo lo que tenemos que hacer es redefinir nuestra función de Fibonacci de la siguiente manera:
Como puede ver, el método
computeIfAbsent
utilizará 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 con respecto al algoritmo tradicional recursivo de árbol.fuente
HashMap
se corrompan los componentes internos, al igual que en bugs.openjdk.java.net/browse/JDK-8172951 y fallaráConcurrentModificationException
en Java 9 ( bugs.openjdk.java.net/browse/JDK-8071667 )Otro ejemplo. Al construir un mapa complejo de mapas, el método computeIfAbsent () es un reemplazo del método get () de map. Mediante el encadenamiento de llamadas computeIfAbsent () juntas, los contenedores faltantes se construyen sobre la marcha mediante las expresiones lambda proporcionadas:
fuente
multi-mapa
Esto es realmente útil si desea crear un multimapa sin recurrir a Google Guava biblioteca de para su implementación de
MultiMap
.Por ejemplo, suponga que desea almacenar una lista de estudiantes que se matricularon en una materia en particular.
La solución normal para esto usando la biblioteca JDK es:
Dado que tiene un código repetitivo, la gente tiende a usar Guava
Mutltimap
.Usando Map.computeIfAbsent, podemos escribir en una sola línea sin guava Multimap de la siguiente manera.
Stuart Marks y Brian Goetz dieron una buena charla sobre esto https://www.youtube.com/watch?v=9uTVXxJjuco
fuente
studentListSubjectWise.stream().collect(Collectors.GroupingBy(subj::getSubjName, Collectors.toList());
Esto produce un multimapa de tipoMap<T,List<T>
en JDK solo que de manera más concisa en mi humilde opinión.