57 votes

Pourquoi list.size ()> 0 est plus lent que list.isEmpty () en Java?

Pourquoi est - list.size()>0 plus lent que l' list.isEmpty() en Java? En d'autres termes pourquoi isEmpty() est préférable à d' size()>0?

Quand je regarde la mise en œuvre, en ArrayList, il semblerait que la vitesse doit être la même:

Liste de tableaux.size()

    /**
     * Returns the number of elements in this list.
     *
     * @return the number of elements in this list
     */
    public int size() {
      return size;
    }

Liste de tableaux.isEmpty()

    /**
     * Returns <tt>true</tt> if this list contains no elements.
     *
     * @return <tt>true</tt> if this list contains no elements
     */
    public boolean isEmpty() {
        return size == 0;
     }

Si nous suffit d'écrire un programme simple pour obtenir le temps de prendre par les deux méthodes, ce cas size() prendra plus de isEmpty() dans tous les cas, pourquoi donc?

Voici mon TestCode;

import java.util.List;
import java.util.Vector;

public class Main {
    public static void main(String[] args) {
        List l=new Vector();
        int i=0;
        for(i=0;i<10000;i++){
            l.add(new Integer(i).toString());
        }
        System.out.println(i);
        Long sTime=System.nanoTime();
        l.size();
        Long eTime=System.nanoTime();
        l.isEmpty();
        Long eeTime=System.nanoTime();
        System.out.println(eTime-sTime);
        System.out.println(eeTime-eTime);
    }
}

Ici, eTime-sTime>eeTime-eTime dans tous les cas. Pourquoi?

103voto

Andrzej Doyle Points 52541

Pour ArrayLists, oui - vous avez raison, les opérations ont (à peu près) le même temps.

Pour les autres implémentations de liste naïfs listes chaînées*, par exemple de comptage de la taille pourrait prendre un temps très long, alors que vous n'en fait qu'il est plus grand que zéro.

Donc, si vous devez absolument savoir que la liste est une implémentation de l' ArrayList et ne pourront jamais changer alors il n'a pas vraiment d'importance; mais:

  1. c'est la mauvaise programmation de la pratique de toute façon de vous contenter d'une mise en œuvre spécifique.
  2. Si les choses changer dans quelques années la ligne avec le code de restructuration, les tests montrent que "ça marche" mais les choses sont en cours d'exécution est moins efficace qu'avant
  3. Même dans le meilleur des cas, size() == 0 est encore plus rapide que d' isEmpty(), donc il n'y a aucune raison impérieuse de toujours utiliser l'ancien.
  4. isEmpty est une définition plus claire de ce qu'il est vraiment et de tests, ce qui rend votre code un peu plus facilement compréhensible.

(Aussi, j'aimerais revoir l'utilisation de NULL dans votre question, le titre, la question elle-même, et ces opérations, n'ont rien à voir avec le fait que toutes les références d'objet sont nulles.)

* J'ai d'abord écrit - LinkedList ici, implictly de référencement de java.util.LinkedList, bien que cette mise en œuvre ne stocker sa longueur de manière explicite, faire la taille() O(1) le fonctionnement ici. Un plus naïf liste liée opération risque de ne pas le faire, et dans le sens plus général il n'y a aucune garantie d'efficacité sur les implémentations de la Liste.

73voto

JRL Points 36674

Votre code de test est défectueux.

Inversez simplement l'ordre, c'est-à-dire appelez isEmpty en premier et taille> 0 seconde et vous obtiendrez le résultat opposé . Cela est dû au chargement de classe, à la mise en cache, etc.

16voto

Robert Munteanu Points 31558

Je suis désolé, mais votre référence est défectueuse. Jetez un œil à la théorie et à la pratique de Java: Anatomie d'un microbenchmark défectueux pour une description générale de la façon d'aborder les benchmarks.


Mise à jour : pour une référence appropriée, vous devriez vous pencher sur Japex .

5voto

wds Points 9910

Vous avez dit:

Ici, eTime-sTime>eeTime-eTime dans tous les cas, Pourquoi?

Tout d'abord, c'est probablement parce que de votre code de test. Vous ne pouvez pas tester la vitesse de l'appel de l'.taille() et l'.isEmpty() en même temps, puisqu'ils ont tous deux de la requête de la même valeur. Les plus susceptibles d'appeler l'.size() a chargé la taille de votre liste dans votre cache du processeur et de l'appel de l'.isEmpty() est beaucoup plus rapide.

Vous pourriez essayer d'appeler l'.taille() un couple de millions de fois et l'.isEmpty() un couple de millions de fois en deux programmes distincts, mais en théorie, le compilateur pourrait seulement optimiser l'écart de tous ces appels puisque vous n'êtes pas en train de faire quelque chose avec les résultats.

Dans tous les cas, la différence de performances entre les deux va être négligeables, en particulier une fois que vous faites la comparaison que vous devez faire pour voir si la liste est vide (l.size() == 0). Probablement le code généré seront presque complètement similaire. Comme certains autres affiches remarquer, vous souhaitez optimiser pour des raisons de lisibilité dans ce cas, pas de vitesse.

edit: je l'ai testé moi-même. C'est assez d'un tirage au sort. size() et isEmpty() utilisé sur Vector ont donné des résultats différents sur les longues courses, ni de battre les autres de manière cohérente. Lorsqu'il est exécuté sur un ArrayList size() semblait plus rapide, mais pas de beaucoup. Ceci est probablement dû au fait que l'accès à l' Vector est synchronisé, de sorte que vous êtes en train de voir en essayant de référence d'accès à ces méthodes est la synchronisation des frais généraux, qui peuvent être très sensibles.

La chose à emporter ici est que, quand vous pouvez essayer d'optimiser un appel de méthode avec quelques nanosecondes différence de temps d'exécution, puis vous avez tout faux. Obtenez de bonnes bases tout d'abord, comme l'utilisation d' Longs où vous devriez être en utilisant long.

2voto

Joachim Sauer Points 133411

Compte tenu de ces deux implémentations, la vitesse devrait être la même, c'est vrai.

Mais ce sont de loin pas le seul possible l'implémentation de ces méthodes. Une primitive liste liée (à ne pas stocker la taille séparément), par exemple, pouvaient réponse isEmpty() beaucoup plus rapide qu'un size() appel.

Plus important encore: isEmpty() décrit votre intention exactement, alors que size()==0 est inutilement complexe (pas extrêmement complexe, bien sûr, mais toute la complexité inutile doit être évitée).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X