Je veux vraiment utiliser Map.computeIfAbsent mais cela fait trop longtemps depuis les lambdas au premier cycle.
Presque directement à partir de la documentation: cela donne un exemple de l'ancienne façon de faire les choses:
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);
}
Et la nouvelle façon:
map.computeIfAbsent(key, k -> new Value(f(k)));
Mais dans leur exemple, je pense que je ne «comprends» pas tout à fait. Comment transformer le code pour utiliser la nouvelle manière lambda d'exprimer cela?
java
dictionary
lambda
java-8
Benjamin H
la source
la source
Réponses:
Supposons que vous ayez le code suivant:
Ensuite, vous verrez le message
creating a value for "snoop"
exactement une fois, car lors de la deuxième invocation,computeIfAbsent
il y a déjà une valeur pour cette clé. Lek
dans l'expression lambdak -> f(k)
est juste un emplacement (paramètre) pour la clé que la carte passera à votre lambda pour calculer la valeur. Ainsi, dans l'exemple, la clé est transmise à l'appel de la fonction.Vous pouvez également écrire:
whoLetDogsOut.computeIfAbsent("snoop", k -> k.isEmpty());
pour obtenir le même résultat sans méthode d'assistance (mais vous ne verrez alors pas la sortie de débogage). Et encore plus simple, car il s'agit d'une simple délégation à une méthode existante que vous pourriez écrire:whoLetDogsOut.computeIfAbsent("snoop", String::isEmpty);
Cette délégation n'a pas besoin d' écrire de paramètres.Pour être plus proche de l'exemple de votre question, vous pouvez l'écrire comme
whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key));
(peu importe si vous nommez le paramètrek
oukey
). Ou écrivez-le commewhoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut);
sitryToLetOut
eststatic
ouwhoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);
sitryToLetOut
est une méthode d'instance.la source
Récemment, je jouais aussi avec cette méthode. J'ai écrit un algorithme mémorisé pour calculer les nombres de Fibonacci qui pourrait servir d'illustration supplémentaire sur la façon d'utiliser la méthode.
Nous pouvons commencer par définir une carte et y mettre les valeurs pour les cas de base, à savoir,
fibonnaci(0)
etfibonacci(1)
:Et pour l'étape inductive, tout ce que nous avons à faire est de redéfinir notre fonction de Fibonacci comme suit:
Comme vous pouvez le voir, la méthode
computeIfAbsent
utilisera l'expression lambda fournie pour calculer le nombre de Fibonacci lorsque le nombre n'est pas présent dans la carte. Cela représente une amélioration significative par rapport à l'algorithme récursif traditionnel.la source
HashMap
la corruption des composants internes de 's, tout comme dans bugs.openjdk.java.net/browse/JDK-8172951 et échouera avecConcurrentModificationException
dans Java 9 ( bugs.openjdk.java.net/browse/JDK-8071667 )Un autre exemple. Lors de la construction d'une carte complexe de cartes, la méthode computeIfAbsent () remplace la méthode get () de la carte. Grâce au chaînage des appels computeIfAbsent (), les conteneurs manquants sont construits à la volée par les expressions lambda fournies:
la source
multi-carte
Ceci est vraiment utile si vous souhaitez créer une multi - carte sans recourir à la bibliothèque Google Guava pour sa mise en œuvre de
MultiMap
.Par exemple, supposons que vous souhaitiez stocker une liste d'étudiants qui se sont inscrits pour une matière particulière.
La solution normale pour cela en utilisant la bibliothèque JDK est:
Puisqu'il a un code standard, les gens ont tendance à utiliser Guava
Mutltimap
.En utilisant Map.computeIfAbsent, nous pouvons écrire sur une seule ligne sans goyave Multimap comme suit.
Stuart Marks et Brian Goetz ont fait une bonne discussion à ce sujet https://www.youtube.com/watch?v=9uTVXxJjuco
la source
studentListSubjectWise.stream().collect(Collectors.GroupingBy(subj::getSubjName, Collectors.toList());
multi-carte en Java 8 (et plus concise) est de simplement faire Cela produit une multi-carte de typeMap<T,List<T>
dans JDK de manière plus concise à mon humble avis.