web-dev-qa-db-fra.com

HashMap vs performances LinkedHashMap en itération sur les valeurs ()

Existe-t-il une différence de performances entre HashMap et LinkedHashMap pour la traversée de la fonction values()?

30
MBZ

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.

39
Ajay George

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.

38
user1016765

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.

4
AlexR

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.

2
Marko Topolnik

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.

2
Louis Wasserman

J'ai essayé dans un UnitTest, itéré les valeurs () 10000 fois, les millisecondes: 806 vs 902. C'est presque la même chose.

2
hongtium