Map
Avec l'introduction des lambdas en Java 1.8, il est possible de mettre à jour une Map
en faisant un seul accès à la Map
.
Dans le cas d'une mise à jour simple, on peut utiliser pour cela les méthodes merge
et computeIfAbsent
.
Le choix de la méthode dépend de la classe des valeurs de la Map
, et en particulier de sa mutabilité.
Map
avec valeurs immutables (1/2)Si les valeurs de la Map
sont immutables (comme dans HashMap<String,Integer>
ou HashMap<String,String>
), on peut utiliser la méthode merge
.
La méthode merge(key,newValue,combinationFunction)
prend la clé, la valeur à ajouter et la fonction qui va combiner l'ancienne et la nouvelle valeur.
HashMap<String, Integer> = new HashMap<>(); var key = "Foo"; var updatedValue = map.merge(key, 1, Integer::sum);
Map
avec valeurs immutables (2/2)Si la mise à jour est plus compliquée qu'une simple combinaison de l'ancienne valeur avec une nouvelle valeur,
on peut utiliser la méthode plus générale compute
.
La méthode compute(key, function)
prend la clé et une fonction permettant de calculer la nouvelle valeur à insérer dans la Map
à partir de la clé et de l'ancienne valeur. La valeur null
est donnée comme ancienne valeur si la clé n'est pas dans la Map
.
HashMap<String, Integer> = new HashMap<>(); var key = "Foo"; var updatedValue = map.compute(key, old -> (old == null) ? 1 : old * old);
Map
avec valeurs mutables (1/2) Regardons maitenant le cas d'une Map
dont les valeurs sont des classes mutables comme HashMap<Long, Data>
avec la classe Data
ci-dessous:
public class Data { public void update(long newValue){ ... } }
Map
avec valeurs mutables (2/3)Le code ci-dessous fait 2 recherches dans la Map
et duplique du code, il ne faut pas le faire :
// CODE A NE PAS FAIRE !!!!!!!! HashMapmap = ... if (!map.contains(key)){ var data = new Data(); data.update(newValue); map.put(data); } else { var data = map.get(key); data.update(newValue); }
Depuis Java 1.8, on peut mettre à jour une Map
avec une seule recherche.
Map
avec valeurs mutables (3/3)On peut utiliser la méthode computeIfAbsent(key,function)
qui prend la clé et une fonction qui donne la valeur à insérer si la clé n'est pas déjà dans la map. Cette méthode insére la valeur donnée par le la fonction si la clé n'est pas dans la map puis renvoie la valeur associée à la clé.
HashMapmap = ... var data = map.computeIfAbsent(key, k -> new Data()); data.update(newValue);
Attention :
put
après la mise à jour car la classe Data
est mutable.putIfAbsent
est un faux ami car elle ne renvoie pas la valeur actuelle de la clé mais l'ancienne valeur.