Mise à jour d'une Map

Rappel

Bonnes pratiques

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 !!!!!!!!
HashMap map = ...
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é.

HashMap map = ...
var data = map.computeIfAbsent(key, k -> new Data());
data.update(newValue);

Attention :

  • Il n'est pas nécessaire de faire un put après la mise à jour car la classe Data est mutable.
  • La méthode putIfAbsent est un faux ami car elle ne renvoie pas la valeur actuelle de la clé mais l'ancienne valeur.