web-dev-qa-db-fra.com

Quelle est la différence entre putIfAbsent et computeIfAbsent dans Java 8 Map?

En lisant des articles intéressants, les gars prétendent que la différence entre les deux fonctions est la suivante:

Les deux fonctions aspirent à ajouter un élément si la clé spécifiée n'est pas déjà présente dans Map.

putIfAbsent ajoute un élément avec la valeur spécifiée, tandis que computeIfAbsent ajoute un élément avec la valeur calculée à l'aide de la clé. http://www.buggybread.com/2014/10/Java-8-difference-between-map.html

Et

Nous avons vu que putIfAbsent supprime le moyen impératif de définir l’instruction if, mais qu’en est-il si le fait de récupérer les articles Java nuit réellement à notre performance?

Pour optimiser cela, nous ne voulons pas aller chercher les articles avant d’être vraiment sûrs d’en avoir besoin - c’est-à-dire qu’il faut savoir si la clé est absente avant d’aller chercher les articles. http://www.deadcoderising.com/2017-02-14-Java-8-declarative-ways-of-modifying-a-map-using-compute-mer-re-replace/

Je ne comprenais pas quelles sont les différences. Pourriez-vous nous en dire plus sur ces deux fonctions?

45
Adelin

Différence n ° 1

computeIfAbsent prend une fonction de mappage, appelée pour obtenir la valeur si la clé est manquante.

putIfAbsent prend directement la valeur.

Si la valeur est coûteuse à obtenir, putIfAbsent la gaspille si la clé existe déjà.

Une valeur "chère" courante est par exemple: new ArrayList<>() pour lorsque vous créez un Map<K, List<V>>, où créer une nouvelle liste lorsque la clé existe déjà (qui rejette ensuite la nouvelle liste) génère des déchets inutiles.


Différence n ° 2

computeIfAbsent renvoie "la valeur actuelle (existante ou calculée) associée à la clé spécifiée, ou null si la valeur calculée est null".

putIfAbsent renvoie "la valeur précédente associée à la clé spécifiée ou la valeur null s'il n'y avait pas de mappage pour la clé".

Ainsi, si la clé existe déjà, ils renvoient la même chose, mais si la clé est manquante, computeIfAbsent renvoie la valeur calculée, tandis que putIfAbsent renvoie null.


Différence # 3

Les deux méthodes définissent "absent" car la clé est manquante ou la valeur existante est nulle, mais:

computeIfAbsent ne mettra pas de valeur nulle si la clé est absente.

putIfAbsent mettra la valeur si la clé est absente, même si la valeur est null.

Cela ne fait aucune différence pour les prochains appels à computeIfAbsent , putIfAbsent et get appels, mais cela fait une différence pour des appels tels que getOrDefault et containsKey .

86
Andreas

Supposons que vous ayez un Map<String,ValueClass>.

map.putIfAbsent("key", new ValueClass());

créera quand même une instance ValueClass, même si la clé "clé" est déjà dans le Map. Cela ne ferait que créer une instance inutile.

D'autre part

map.computeIfAbsent("key", k -> new ValueClass());

créera une instance ValueClass uniquement si la clé "clé" n'est pas déjà dans la variable Map (ou est mappée sur une valeur null.).

Par conséquent, computeIfAbsent est plus efficace.

putIfAbsent est équivalent à:

ValueClass value = new ValueClass();
if (map.get("key") == null) {
    map.put("key",value);
}

tandis que computeIfAbsent est équivalent à:

if (map.get("key") == null) {
    map.put("key",new ValueClass());
}

Une autre petite différence entre les deux méthodes est que computeIfAbsent ne mettra pas de valeur null pour une clé absente. putIfAbsent sera.

42
Eran

Vous pouvez comprendre la différence en regardant attentivement les signatures de la méthode:

  • putIfAbsent prend une clé et une valeur et la met dans la carte s'il n'y a pas de valeur pour cette clé dans la carte.
  • computeIfAbsent prend une clé et un Function. S'il n'y a pas de valeur pour cette clé dans la carte, la fonction est appelée pour créer la valeur, qui est ensuite placée dans la carte.

Si vous avez déjà la valeur, utilisez putIfAbsent.

Si vous n'avez pas encore la valeur et que la création de la valeur est une opération coûteuse (par exemple, la valeur doit être recherchée dans une base de données), utilisez computeIfAbsent pour que l'opération coûteuse ne nécessite pas à effectuer si la carte contient déjà une valeur pour la clé spécifiée.

3
Jesper

Peut-être que les implémentations par défaut peuvent clarifier un peu plus ...

default V putIfAbsent​(K key, V value) L'implémentation par défaut est équivalente à, pour cette carte:

 V v = map.get(key);
  if (v == null)
      v = map.put(key, value);
  return v;

D'autre part:

default V computeIfAbsent​(K key,
                          Function<? super K,? extends V> mappingFunction)

est équivalent à:

if (map.get(key) == null) {
     V newValue = mappingFunction.apply(key);
     if (newValue != null)
         map.put(key, newValue);
}
2
zlakad

V putIfAbsent(K key, V value) - Si la clé spécifiée n'est pas déjà associée à une valeur (ou si elle est mappée sur null), tente de calculer sa valeur à l'aide de la fonction de mappage donnée et la saisit dans cette mappe sauf si la valeur est null.

V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) - Si la clé spécifiée n'est pas déjà associée à une valeur (ou si elle est mappée sur null), tente de calculer sa valeur à l'aide de la fonction de mappage donnée et la saisit dans cette mappe sauf si la valeur est null.

La lecture de la documentation peut vous donner une réponse plus évidente. https://docs.Oracle.com/javase/8/docs/api/Java/util/Map.html

1
minotna