Existe-t-il une différence de performances entre HashMap
et LinkedHashMap
pour la traversée de la fonction values()
?
Je pense que le LinkedHashMap
doit être plus rapide en traversée en raison d'une implémentation supérieure de nextEntry
dans son Iterator
Voici pourquoi:
Partons pas à pas de l'implémentation de values
.
L'implémentation de HashMap
de values
est la suivante:
public Collection<V> values() {
Collection<V> vs = values;
return (vs != null ? vs : (values = new Values()));
}
LinkedHashMap
s'étend de HashMap
et hérite de la même implémentation.
La différence réside dans l'implémentation de Iterator
pour le Values
dans les deux.
pour HashMap
il s'étend de Java.util.HashMap.HashIterator
private final class ValueIterator extends HashIterator<V> {
public V next() {
return nextEntry().value;
}
}
mais pour LinkedHashMap
cela s'étend de Java.util.LinkedHashMap.LinkedHashIterator
private class ValueIterator extends LinkedHashIterator<V> {
public V next() { return nextEntry().value; }
}
donc différence se résume essentiellement à l'implémentation de nextEntry
.
Pour LinkedHashMap
, il s'agit simplement d'appeler e.after où e est le Entry
, mais pour HashMap
, il y a un peu de travail à parcourir le tableau Entry[]
Pour trouver le prochain suivant.
MISE À JOUR : Code pour nextEntry()
dans HashMap
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
L'entrée [] n'est pas un magasin contigu. (Il pourrait y avoir des valeurs nulles entre les deux). Si vous jetez un œil au code ci-dessus, ce qu'il fait est de pointer à côté de courant et de trouver le suivant suivant en itérant sur l'entrée [].
Mais Je pense que ce gain de performances se fera au détriment de l'insertion. Découvrez la méthode addEntry
dans les deux classes comme exercice.
J'ai écrit un petit programme de profilage créant 1 million de clés (Integer) vs Boolean.TRUE, en répétant 100 fois. Trouvé ce qui suit:
HashMap:-
Create: 3.7sec
Iterate: 1.1sec
Access: 1.5sec
Total: 6.2sec
LinkedHashMap:-
Create: 4.7sec (30% slower)
Iterate: 0.5sec (50% faster)
Access: 0.8sec (50% faster)
Total : 6.0sec
La récupération de place N'EST PAS effectuée, donc pollue quelque peu les chiffres, mais je pense que LinkedHashMap a l'avantage sur HashMap et je vais l'utiliser dans le futur code.
Cela n'a presque pas d'importance. La question est: de quoi avez-vous besoin. Si l'ordre des éléments est pertinent, vous devez utiliser LinkedHashMap
. Sinon, vous n'en avez tout simplement pas besoin, utilisez donc HashMap
.
Le meilleur conseil serait "N'ayez pas peur de l'essayer" mais je suis sûr qu'ils sont très similaires. L'obtention de l'ensemble de valeurs est O(1) et il en est de même pour chaque étape de l'itérateur. L'itération à travers une liste chaînée est aussi triviale que l'itération à travers les compartiments de hachage, avec un petit Edge s possible en faveur de la liste chaînée.
Oui, il y aura la même différence de performances que vous obtenez dans toutes les itérations sur HashMap
contre LinkedHashMap
: HashMap
prendra du temps proportionnel au nombre d'entrées plus la taille de la table de hachage, et LinkedHashMap
prendra juste un temps proportionnel au nombre d'entrées.
J'ai essayé dans un UnitTest, itéré les valeurs () 10000 fois, les millisecondes: 806 vs 902. C'est presque la même chose.