Tableau ou liste en Java. Ce qui est plus rapide?

je dois garder des milliers de chaînes en mémoire pour être accédé en série en Java. Dois-je les stocker dans un tableau ou utiliser une sorte de liste ?

puisque les tableaux conservent toutes les données dans un morceau contigu de mémoire (Contrairement aux listes), l'utilisation d'un tableau pour stocker des milliers de chaînes causerait-elle des problèmes ?

réponse: le consensus général est que la différence de performance est mineure. L'interface de liste fournit plus flexibilité.

316
demandé sur Roman Nikitchenko 2009-04-04 09:57:28

30 réponses

je suggère que vous utilisiez un profileur pour tester ce qui est plus rapide.

mon opinion personnelle est que vous devriez utiliser des listes.

je travaille sur une grande base de code et un groupe précédent de développeurs utilisé tableaux partout . Cela rendait le code très rigide. Après en avoir changé de gros morceaux en listes, nous n'avons remarqué aucune différence de vitesse.

334
répondu Fortyrunner 2009-04-04 06:18:14

la manière Java est que vous devriez considérer quelles données abstraction conviennent le plus à vos besoins. Rappelez-vous que dans Java une liste est un Abstrait, pas un type de données concret. Vous devez déclarer les chaînes comme une liste, puis l'initialiser en utilisant L'implémentation ArrayList.

List<String> strings = new ArrayList<String>();

cette séparation du type de données abstraites et de la mise en œuvre spécifique est l'un des aspects clés de la programmation orientée objet.

An ArrayList implémente le type de données abstraites List en utilisant un tableau comme implémentation sous-jacente. La vitesse d'accès est pratiquement identique à un tableau, avec les avantages supplémentaires de pouvoir ajouter et soustraire des éléments à une liste (bien qu'il s'agisse d'une opération O(n) avec un ArrayList) et que si vous décidez de changer l'implémentation sous-jacente plus tard, vous le pouvez. Par exemple, si vous réalisez que vous avez besoin d'un accès synchronisé, vous pouvez changer l'implémentation en un vecteur sans réécrire tout votre code.

en fait, L'ArrayList a été spécifiquement conçu pour remplacer la construction de tableau de bas niveau dans la plupart des contextes. Si Java avait été conçu aujourd'hui, il est tout à fait possible que les tableaux aient été complètement exclus en faveur de la construction ArrayList.

puisque les tableaux conservent toutes les données dans un morceau contigu de mémoire (Contrairement aux listes), l'utilisation d'un tableau pour stocker des milliers de chaînes causerait-elle des problèmes ?

En Java, toutes les collections de stocker uniquement les références à des objets, et non les objets eux-mêmes. Les tableaux et les tableaux stockeront quelques milliers de références dans un tableau contigu, de sorte qu'ils sont essentiellement identiques. Vous pouvez considérer qu'un bloc contigu de quelques milliers de références 32 bits sera toujours disponible sur du matériel moderne. Cela ne garantit pas que vous ne serez pas manquer de mémoire tout à fait, bien sûr, juste que le bloc contigu de la mémoire exigence n'est pas difficile à accomplir.

152
répondu cygil 2009-04-05 00:19:54

vous devriez préférer les types génériques aux tableaux. Comme mentionné par d'autres, les tableaux sont rigides et n'ont pas le pouvoir expressif des types génériques. (Ils soutiennent cependant runtime typechecking, mais qui se mélange mal avec les types génériques.)

, Mais, comme toujours, lors de l'optimisation, vous devez toujours suivre ces étapes:

  • ne pas optimiser jusqu'à ce que vous avez une belle, propre, et de travail version de votre code. Le passage à des types génériques pourrait très bien être motivé à cette étape déjà.
  • Quand vous avez une version qui est agréable et propre, décider s'il est assez rapide.
  • Si elle n'est pas assez rapide, mesurer ses performances . Cette étape est importante pour deux raisons. Si vous ne mesurez pas, vous ne (1) connaissez pas l'impact des optimisations que vous faites et (2) savez où optimiser.
  • Optimiser la partie la plus chaude de votre code.
  • Mesurer à nouveau. c'est tout aussi important que de mesurer avant. Si l'optimisation n'a pas améliorer les choses, revenir . Rappelez-vous, le code sans l'optimisation était propre, agréable, et de travail.
90
répondu JesperE 2015-05-06 01:35:51

bien que les réponses proposant D'utiliser ArrayList aient un sens dans la plupart des scénarios, la question réelle de la performance relative n'a pas vraiment été répondu.

Il ya quelques choses que vous pouvez faire avec un tableau:

  • créer
  • définir une option
  • obtenir un article
  • clone/copie

Conclusion générale

bien que les opérations get et set soient un peu plus lentes sur un ArrayList (resp. 1 et 3, l'ordre de la nanoseconde par appel sur ma machine), il y a très peu de frais généraux de l'utilisation d'une liste de tableaux vs un tableau pour tout usage non intensif. il y a cependant quelques choses à garder à l'esprit:

  • les opérations de redimensionnement sur une liste (lors de l'appel list.add(...) ) sont coûteuses et il faut essayer de régler la capacité initiale à un niveau adéquat lorsque c'est possible (notez que la même question se pose lorsque vous utilisez un tableau)
  • lorsqu'il s'agit de primitives, les matrices peuvent être beaucoup plus rapides car elles permettent d'éviter de nombreuses conversions de boxe /désabonnement.""
  • une application qui obtient/fixe seulement des valeurs dans un ArrayList (pas très commun!) pourrait voir un gain de performance de plus de 25% en passant à un tableau

résultats détaillés

Voici les résultats que j'ai mesurés pour ces trois opérations en utilisant la bibliothèque de référence JMH (temps en nanosecondes) avec JDK 7 sur une machine de bureau x86 standard. Notez que ArrayList ne sont jamais redimensionnés dans les tests pour s'assurer que les résultats sont comparables. Référence code disponible ici .

Tableau/Liste De Tableaux De La Création

j'ai effectué 4 tests, en exécutant les énoncés suivants:

  • createArray1: Integer[] array = new Integer[1];
  • createList1: List<Integer> list = new ArrayList<> (1);
  • createArray10000: Integer[] array = new Integer[10000];
  • createList10000: List<Integer> list = new ArrayList<> (10000);

Résultats (en nanosecondes par appel, de confiance à 95%):

a.p.g.a.ArrayVsList.CreateArray1         [10.933, 11.097]
a.p.g.a.ArrayVsList.CreateList1          [10.799, 11.046]
a.p.g.a.ArrayVsList.CreateArray10000    [394.899, 404.034]
a.p.g.a.ArrayVsList.CreateList10000     [396.706, 401.266]

Conclusion: aucune différence notable .

de lancer des opérations

j'ai effectué 2 tests, en exécutant les énoncés suivants:

  • getList: return list.get(0);
  • getArray: return array[0];

Résultats (en nanosecondes par appel, de confiance à 95%):

a.p.g.a.ArrayVsList.getArray   [2.958, 2.984]
a.p.g.a.ArrayVsList.getList    [3.841, 3.874]

Conclusion: obtenir à partir d'un réseau est environ 25% plus rapide que d'obtenir à partir d'un ArrayList, bien que la différence soit seulement de l'ordre d'une nanoseconde.

ensemble des opérations de

j'ai effectué 2 tests, en exécutant les énoncés suivants:

  • setList: list.set(0, value);
  • setArray: array[0] = value;

résultats (en nanosecondes par appel):

a.p.g.a.ArrayVsList.setArray   [4.201, 4.236]
a.p.g.a.ArrayVsList.setList    [6.783, 6.877]

Conclusion: les opérations de jeu sur les tableaux sont environ 40% plus rapides que sur les listes, mais, comme pour get, chaque jeu l'opération prend quelques nanosecondes - donc pour que la différence atteigne 1 seconde, il faudrait mettre des articles dans la liste/le tableau des centaines de millions de fois!

clone/copie

le constructeur de copies D'ArrayList délègue à Arrays.copyOf ainsi la performance est identique à la copie d'array (copier un array via clone , Arrays.copyOf ou System.arrayCopy ne fait aucune différence de performance-du point de vue de la performance ).

80
répondu assylias 2017-05-23 12:10:29

je suppose que l'affiche originale vient d'un arrière-plan C++/STL qui cause une certaine confusion. En C++ std::list est une liste doublement liée.

en Java [java.util.]List est une interface sans implémentation (classe abstraite pure en termes C++). List peut être une liste doublement liée - java.util.LinkedList est fourni. Cependant, 99 fois sur 100 quand vous voulez un faire un nouveau List , vous voulez utiliser java.util.ArrayList à la place, qui est l'équivalent approximatif de c++ std::vector . Il existe d'autres implémentations standard, comme celles retournées par java.util.Collections.emptyList() et java.util.Arrays.asList() .

du point de vue de la performance, il y a un très petit succès en passant par une interface et un objet supplémentaire, cependant runtime lining signifie que cela a rarement une signification. Rappelez-vous également que String sont généralement un objet plus tableau. Donc, pour chaque entrée, vous avez probablement deux autres objets. En C++ std::vector<std::string> , bien que la copie par valeur sans pointeur en tant que tel, les tableaux de caractères formeront un objet pour la chaîne (et ceux-ci ne seront généralement pas partagés).

si ce code particulier est vraiment sensible aux performances, vous pouvez créer un seul tableau char[] (ou même byte[] ) pour tous les caractères de toutes les chaînes, puis un tableau de offsets. IIRC, voici comment javac est implémenté.

22
répondu Tom Hawtin - tackline 2015-10-07 12:07:54

Eh bien, tout d'abord, il est utile de clarifier ce que vous voulez dire par "liste" dans le sens classique des structures de données de SCI (c'est-à-dire une liste liée) ou vous voulez dire java.util.Liste? Si vous entendez un java.util.List, c'est une interface. Si vous voulez utiliser un tableau, utilisez simplement L'implémentation ArrayList et vous obtiendrez un comportement et une sémantique de type tableau. Le problème est résolu.

si vous voulez dire un tableau vs une liste liée, c'est un argument légèrement différent pour lequel nous revenons à Big O (voici un explication en anglais simple si ce terme n'est pas familier.

Array;

  • Random Access: O (1);
  • insérer: O (n);
  • Supprimer: O (n).

Liste Liée:

  • Random Access: O (n);
  • Insérer: O (1);
  • Supprimer: O (1).

Donc vous choisissez celui qui convient le mieux à la façon dont vous redimensionnez votre tableau. Si vous redimensionnez, insérez et supprimez beaucoup alors peut-être une liste liée est un meilleur choix. Il en va de même si l'accès aléatoire est rare. Vous mentionnez accès série. Si vous faites principalement des accès série avec très peu de modifications, alors il n'a probablement pas d'importance ce que vous choisissez.

les listes de liens ont un plafond légèrement plus élevé puisque, comme vous le dites, vous avez affaire à des blocs de mémoire potentiellement non contigus et (effectivement) pointeurs vers l'élément suivant. Ce n'est probablement pas un facteur important à moins que vous avez affaire à des millions d'entrées cependant.

11
répondu cletus 2017-05-23 10:31:12

j'ai écrit un petit benchmark pour comparer les ArrayLists avec les Arrays. Sur mon vieil ordinateur portable, le temps de traverser un arraylist de 5000 éléments, 1000 fois, était environ 10 millisecondes plus lent que le code de tableau équivalent.

donc, si vous ne faites rien d'autre que d'itérer la liste, et que vous le faites souvent, alors peut-être ça vaut la peine d'être optimisé. Sinon, j'utiliserais la liste, parce que ça le rendra plus facile quand vous do nécessité d'optimiser le code.

n.b. J' a avis que l'utilisation de for String s: stringsList a été d'environ 50% plus lent que d'utiliser un vieux style de boucle pour accéder à la liste. Aller à la figure... Voici les deux fonctions que j'ai chronométrées; le tableau et la liste ont été remplis avec 5000 chaînes aléatoires (différentes).

private static void readArray(String[] strings) {
    long totalchars = 0;
    for (int j = 0; j < ITERATIONS; j++) {
        totalchars = 0;
        for (int i = 0; i < strings.length; i++) {
            totalchars += strings[i].length();

        }
    }
}

private static void readArrayList(List<String> stringsList) {
    long totalchars = 0;
    for (int j = 0; j < ITERATIONS; j++) {
        totalchars = 0;
        for (int i = 0; i < stringsList.size(); i++) {
            totalchars += stringsList.get(i).length();
        }
    }
}
11
répondu Chris May 2009-04-04 14:44:33

je suis d'accord que dans la plupart des cas, vous devriez choisir la souplesse et l'élégance des tableaux plutôt que des tableaux - et dans la plupart des cas, l'impact sur la performance du programme sera négligeable.

cependant, si vous faites constante, itération lourde avec peu de changement structurel (pas d'ajouts et de suppressions) pour, par exemple, le rendu de graphiques logiciels ou une machine virtuelle personnalisée, mes tests de benchmarking d'accès séquentiels montrent que les tableaux sont 1,5 fois plus lents que les tableaux sur mon système (Java 1.6 sur mon iMac d'un an).

code:

import java.util.*;

public class ArrayVsArrayList {
    static public void main( String[] args ) {

        String[] array = new String[300];
        ArrayList<String> list = new ArrayList<String>(300);

        for (int i=0; i<300; ++i) {
            if (Math.random() > 0.5) {
                array[i] = "abc";
            } else {
                array[i] = "xyz";
            }

            list.add( array[i] );
        }

        int iterations = 100000000;
        long start_ms;
        int sum;

        start_ms = System.currentTimeMillis();
        sum = 0;

        for (int i=0; i<iterations; ++i) {
          for (int j=0; j<300; ++j) sum += array[j].length();
        }

        System.out.println( (System.currentTimeMillis() - start_ms) + " ms (array)" );
        // Prints ~13,500 ms on my system

        start_ms = System.currentTimeMillis();
        sum = 0;

        for (int i=0; i<iterations; ++i) {
          for (int j=0; j<300; ++j) sum += list.get(j).length();
        }

        System.out.println( (System.currentTimeMillis() - start_ms) + " ms (ArrayList)" );
        // Prints ~20,800 ms on my system - about 1.5x slower than direct array access
    }
}
11
répondu AbePralle 2017-03-21 18:46:29

non, parce que techniquement, le tableau ne stocke que la référence aux cordes. Les chaînes elles-mêmes sont attribuées à un endroit différent. Pour un millier d'articles, je dirais qu'une liste serait mieux, elle est plus lente, mais elle offre plus de flexibilité et elle est plus facile à utiliser, surtout si vous allez les redimensionner.

6
répondu CookieOfFortune 2009-04-04 06:02:00

si vous en avez des milliers, envisagez d'utiliser un trie. Un trie est une structure arborescente qui fusionne les préfixes communs de la chaîne stockée.

par exemple, si les cordes étaient

intern
international
internationalize
internet
internets

La trie de stocker:

intern
 -> "151910920"
 international
 -> "151910920"
 -> ize"151910920"
 net
 ->"151910920"
 ->s"151910920"

les chaînes nécessitent 57 caractères (y compris le terminateur nul, '\0') pour le stockage, plus quelle que soit la taille de l'objet String qui les contient. (En vérité, nous devrions probablement ronde toutes les tailles jusqu'à des multiples de 16, mais...) Appeler 57 + 5 = 62 octets, à peu près.

le trie nécessite 29 (y compris le terminateur null, '\0') pour le stockage, plus la taille des noeuds trie, qui sont un ref à un tableau et une liste de noeuds enfant trie.

pour cet exemple, cela ressort probablement à peu près pareil; pour des milliers, cela ressort probablement moins tant que vous avez des préfixes communs.

maintenant, en utilisant le tri dans un autre code, vous devrez passer à String, probablement en utilisant un StringBuffer comme intermédiaire. Si beaucoup de cordes sont utilisées à la fois comme cordes, en dehors du trie, c'est une perte.

mais si vous n'en utilisez que quelques-uns à la fois -- par exemple, pour chercher dans un dictionnaire -- le trie peut vous faire gagner beaucoup d'espace. Certainement moins d'espace que de les stocker dans un HashSet.

vous dites que vous y accédez "en série" -- si cela signifie en ordre alphabétique, le trie aussi évidemment vous donne l'ordre alphabétique pour gratuit, si vous parcourir en profondeur d'abord.

5
répondu tpdi 2009-04-05 00:55:14

mise à jour:

comme Mark l'a noté, il n'y a pas de différence significative après l'échauffement de JVM (plusieurs essais réussis). Vérifié avec le tableau recréé ou même un nouveau passage commençant avec une nouvelle ligne de matrice. Avec une grande probabilité ce signe tableau simple avec l'accès d'index n'est pas à utiliser en faveur des collections.

reste premier 1-2 passe simple tableau est de 2 à 3 fois plus rapide.

ORIGINAL POST:

Trop de mots pour le sujet est trop simple à vérifier. sans aucun tableau de questions est plusieurs fois plus rapide que n'importe quel conteneur de classe . Je passe à cette question en cherchant des alternatives pour ma section critique de performance. Voici le code prototype que j'ai construit pour vérifier la situation réelle:

import java.util.List;
import java.util.Arrays;

public class IterationTest {

    private static final long MAX_ITERATIONS = 1000000000;

    public static void main(String [] args) {

        Integer [] array = {1, 5, 3, 5};
        List<Integer> list = Arrays.asList(array);

        long start = System.currentTimeMillis();
        int test_sum = 0;
        for (int i = 0; i < MAX_ITERATIONS; ++i) {
//            for (int e : array) {
            for (int e : list) {
                test_sum += e;
            }
        }
        long stop = System.currentTimeMillis();

        long ms = (stop - start);
        System.out.println("Time: " + ms);
    }
}

Et voici la réponse:

basé sur array (la ligne 16 est active):

Time: 7064

sur la base de la liste (la ligne 17 est active):

Time: 20950

encore un commentaire sur "faster"? C'est tout à fait compris. La question est quand environ 3 fois plus rapide est mieux pour vous que la flexibilité de la liste. Mais c'est une autre question. D'ailleurs, j'ai vérifié cela aussi basé sur Construit manuellement ArrayList . Presque le même résultat.

5
répondu Roman Nikitchenko 2013-10-24 09:02:12

Puisqu'il y a déjà beaucoup de bonnes réponses ici, je voudrais vous donner quelques autres informations de vue pratique, qui est comparaison de performance d'insertion et d'itération : tableau primitif vs liste liée en Java.

il s'agit d'une simple vérification de performance.

ainsi, le résultat dépendra de la performance de la machine.

code Source utilisé à cette fin est le suivant:

import java.util.Iterator;
import java.util.LinkedList;

public class Array_vs_LinkedList {

    private final static int MAX_SIZE = 40000000;

    public static void main(String[] args) {

        LinkedList lList = new LinkedList(); 

        /* insertion performance check */

        long startTime = System.currentTimeMillis();

        for (int i=0; i<MAX_SIZE; i++) {
            lList.add(i);
        }

        long stopTime = System.currentTimeMillis();
        long elapsedTime = stopTime - startTime;
        System.out.println("[Insert]LinkedList insert operation with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");

        int[] arr = new int[MAX_SIZE];

        startTime = System.currentTimeMillis();
        for(int i=0; i<MAX_SIZE; i++){
            arr[i] = i; 
        }

        stopTime = System.currentTimeMillis();
        elapsedTime = stopTime - startTime;
        System.out.println("[Insert]Array Insert operation with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");


        /* iteration performance check */

        startTime = System.currentTimeMillis();

        Iterator itr = lList.iterator();

        while(itr.hasNext()) {
            itr.next();
            // System.out.println("Linked list running : " + itr.next());
        }

        stopTime = System.currentTimeMillis();
        elapsedTime = stopTime - startTime;
        System.out.println("[Loop]LinkedList iteration with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");


        startTime = System.currentTimeMillis();

        int t = 0;
        for (int i=0; i < MAX_SIZE; i++) {
            t = arr[i];
            // System.out.println("array running : " + i);
        }

        stopTime = System.currentTimeMillis();
        elapsedTime = stopTime - startTime;
        System.out.println("[Loop]Array iteration with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");
    }
}

le résultat de Performance est ci-dessous:

enter image description here

5
répondu boraseoksoon 2016-12-21 19:10:31

rappelez-vous qu'un ArrayList encapsule un tableau, donc il y a peu de différence par rapport à l'utilisation d'un tableau primitif (sauf pour le fait qu'une liste est beaucoup plus facile à travailler avec en java).

le seul moment où il est logique de préférer un tableau à un ArrayList est quand vous stockez des primitives, i.e. byte, int, etc et vous avez besoin de l'efficacité spatiale particulière que vous obtenez en utilisant des tableaux primitifs.

4
répondu Nuoji 2009-04-04 11:42:25

tableau vs. liste le choix n'est pas si important (compte tenu de la performance) dans le cas de stocker des objets string. Parce que array et list stockeront des références d'objets string, pas les objets réels.

  1. si le nombre de chaînes est presque constant, utilisez un tableau (ou un tableau). Mais si le nombre varie trop, vous feriez mieux d'utiliser LinkedList.
  2. S'il y a (ou s'il y aura) un besoin d'ajouter ou de supprimer des éléments dans middle, alors vous devez certainement utiliser LinkedList.
4
répondu Emre 2009-04-04 14:29:45

Si vous savez à l'avance la taille des données est alors un tableau sera plus rapide.

une liste est plus souple. Vous pouvez utiliser un ArrayList qui est soutenu par un tableau.

3
répondu TofuBeer 2009-04-04 06:00:50
La liste

est plus lente que les tableaux.Si vous avez besoin d'efficacité, utilisez des tableaux.Si vous avez besoin de flexibilité utilisez la liste.

3
répondu Warrior 2009-04-04 06:04:15

It vous pouvez vivre avec une taille fixe, les tableaux seront plus rapides et auront besoin de moins de mémoire.

si vous avez besoin de la flexibilité de L'interface de liste avec l'ajout et la suppression d'éléments, la question reste de savoir quelle implémentation vous devez choisir. Souvent ArrayList est recommandé et utilisé pour tous les cas, mais ArrayList a également ses problèmes de performance si les éléments au début ou au milieu de la liste doivent être supprimés ou insérés.

You par conséquent, peut vouloir jeter un oeil à http://java.dzone.com/articles/gaplist-%E2%80%93-lightning-fast-list qui introduit GapList. Cette nouvelle implémentation de liste allie les forces de ArrayList et de LinkedList, ce qui donne de très bonnes performances pour presque toutes les opérations.

3
répondu Thomas Mauch 2012-10-19 11:10:24

dépend de la mise en œuvre. il est possible qu'un tableau de types primitifs soit plus petit et plus efficace que ArrayList. C'est parce que le tableau stockera les valeurs directement dans un bloc contigu de mémoire, tandis que l'implémentation ArrayList la plus simple stockera des pointeurs vers chaque valeur. Sur une plateforme 64 bits en particulier, cela peut faire une énorme différence.

bien sûr, il est possible pour la jvm d'avoir un cas particulier pour ce dans ce cas, la performance sera la même.

2
répondu JRalph 2010-09-11 14:57:15
La liste

est la méthode préférée en java 1.5 et au-delà car elle peut utiliser des génériques. Les tableaux ne peuvent pas avoir de génériques. Les tableaux ont aussi une longueur prédéfinie, qui ne peut pas croître dynamiquement. L'initialisation d'un tableau avec une grande taille n'est pas une bonne idée. ArrayList est la façon de déclarer un tableau avec des génériques et il peut croître dynamiquement. Mais si supprimer et insérer est utilisé plus fréquemment, alors la liste liée est la structure de données la plus rapide à utiliser.

2
répondu Shehan Simen 2013-12-04 22:54:25

tableaux recommandés partout vous pouvez les utiliser à la place de la liste, surtout dans le cas où si vous savez le nombre d'articles et la taille ne serait pas changer.

voir Oracle Java best practice: http://docs.oracle.com/cd/A97688_16/generic.903/bp/java.htm#1007056

bien sûr, si vous avez besoin ajouter et supprimer des objets de la collection plusieurs fois des listes d'utilisation facile.

2
répondu Nik 2014-02-19 06:37:00

ArrayList stocke ses articles dans un tableau Object[] et utilise la méthode non typée toArray qui est beaucoup plus rapide (la barre bleue) que celle dactylographiée. C'est typesafe puisque le tableau non typé est enveloppé dans le type générique ArrayList<T> qui est vérifié par le compilateur.

enter image description here

Ce graphique montre un benchmark avec n = 5 sur Java 7. Cependant, le tableau ne change pas beaucoup avec plus d'éléments ou un autre VM. Les frais généraux du CPU ne semblent peut-être pas drastiques, mais ils s'additionnent. Les Chances sont que les consommateurs d'un tableau doivent le convertir en une collection afin de faire quoi que ce soit avec elle, puis convertir le résultat de nouveau à un tableau pour l'alimenter dans une autre méthode d'interface etc L'utilisation d'un simple ArrayList au lieu d'un tableau améliore les performances, sans ajouter beaucoup d'empreinte. ArrayList ajoute un overhead constant de 32 octets au tableau enveloppé. Par exemple, un array avec dix objets nécessite 104 octets, un ArrayList 136 octets.

cette opération se déroule en temps constant, donc elle est beaucoup plus rapide que l'une des précédentes (barre jaune). Ce n'est pas la même chose qu'une copie défensive. Une collecte non modifiable changera lorsque vos données internes changeront. Si cela se produit, les clients peuvent courir dans un ConcurrentModificationException tout en itérant sur les éléments. Il peut être considéré comme une mauvaise conception qu'une interface fournit des méthodes qui lancent un UnsupportedOperationException à l'exécution. Cependant, au moins pour un usage interne, cette méthode peut être une alternative de haute performance à une copie défensive – quelque chose qui n'est pas possible avec les tableaux.

2
répondu Show Stopper 2015-11-20 16:28:16

aucune des réponses ne contenait d'information qui m'intéressait - balayage répétitif du même tableau à plusieurs reprises. J'ai dû créer un test JMH pour ça.

Résultats (Java 1.8.0_66 x32, l'itération simple tableau est au moins 5 fois plus rapide que ArrayList):

Benchmark                    Mode  Cnt   Score   Error  Units
MyBenchmark.testArrayForGet  avgt   10   8.121 ? 0.233  ms/op
MyBenchmark.testListForGet   avgt   10  37.416 ? 0.094  ms/op
MyBenchmark.testListForEach  avgt   10  75.674 ? 1.897  ms/op

Test

package my.jmh.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

@State(Scope.Benchmark)
@Fork(1)
@Warmup(iterations = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class MyBenchmark {

    public final static int ARR_SIZE = 100;
    public final static int ITER_COUNT = 100000;

    String arr[] = new String[ARR_SIZE];
    List<String> list = new ArrayList<>(ARR_SIZE);

    public MyBenchmark() {
        for( int i = 0; i < ARR_SIZE; i++ ) {
            list.add(null);
        }
    }

    @Benchmark
    public void testListForEach() {
        int count = 0;
        for( int i = 0; i < ITER_COUNT; i++ ) {
            for( String str : list ) {
                if( str != null )
                    count++;
            }
        }
        if( count > 0 )
            System.out.print(count);
    }

    @Benchmark
    public void testListForGet() {
        int count = 0;
        for( int i = 0; i < ITER_COUNT; i++ ) {
            for( int j = 0; j < ARR_SIZE; j++ ) {
                if( list.get(j) != null )
                    count++;
            }
        }
        if( count > 0 )
            System.out.print(count);
    }

    @Benchmark
    public void testArrayForGet() {
        int count = 0;
        for( int i = 0; i < ITER_COUNT; i++ ) {
            for( int j = 0; j < ARR_SIZE; j++ ) {
                if( arr[j] != null )
                    count++;
            }
        }
        if( count > 0 )
            System.out.print(count);
    }

}
2
répondu Xtra Coder 2016-06-01 20:00:14

des "Milliers" n'est pas un grand nombre. Quelques milliers de paragraphe chaînes de longueur sont de l'ordre de quelques mo en taille. Si tout ce que vous voulez faire est d'accéder à ces séries, utilisez une liste immuable à un seul lien .

2
répondu Apocalisp 2016-06-10 16:59:45

ne tombez pas dans le piège de l'optimisation sans une analyse comparative appropriée. Comme d'autres ont suggéré d'utiliser un profileur avant de faire n'importe quelle hypothèse.

les différentes structures de données que vous avez énumérées ont des fins différentes. Une liste est très efficace pour insérer des éléments au début et à la fin, mais souffre beaucoup lors de l'accès à des éléments aléatoires. Un tableau a le stockage fixe mais fournit l'accès rapide aléatoire. Enfin un ArrayList améliore l'interface à un tableau en lui permettant de grandir. Normalement, la structure de données à utiliser devrait être dictée par la façon dont les données stockées seront accessibles ou ajoutées.

à propos de la consommation de mémoire. Vous semblez être un mélange de certaines choses. Un tableau vous donnera seulement un morceau continu de mémoire pour le type de données que vous avez. N'oubliez pas que java a des types de données fixes: booléen, char, int, long, float et Object (Cela inclut tous les objets, même un tableau est un objet). Cela signifie que si vous déclarez une tableau de chaînes de caractères [1000] ou myObject myObjects [1000] vous obtenez seulement un 1000 boîtes de mémoire assez grandes pour stocker l'emplacement (références ou pointeurs) des objets. Vous n'avez pas un 1000 boîtes de mémoire assez grand pour s'adapter à la taille des objets. N'oubliez pas que vos objets sont d'abord créés avec "nouveau". C'est quand l'allocation de mémoire est faite et plus tard une référence (leur adresse mémoire) est stockée dans le tableau. L'objet n'est pas copié dans le tableau seulement c'est une référence.

1
répondu potyl 2009-04-04 06:39:46

Je ne pense pas que cela fasse une réelle différence pour les cordes. Ce qui est contigu dans un tableau de cordes est les références aux cordes, les cordes elles-mêmes sont stockées à des endroits aléatoires dans la mémoire.

tableaux vs. listes peuvent faire une différence pour les types primitifs, pas pour les objets. si vous savez à l'avance le nombre d'éléments, et n'ont pas besoin de flexibilité, un tableau de millions d'entiers ou doubles sera plus efficace en mémoire et de manière marginale dans la vitesse qu'une liste, parce qu'en effet ils seront stockés de façon continue et accessibles instantanément. C'est pourquoi Java utilise encore des tableaux de caractères pour les chaînes, des tableaux d'ints pour les données d'image, etc.

1
répondu PhiLho 2009-04-04 08:49:47
Le tableau

est plus rapide - toute la mémoire est pré-allouée à l'avance.

1
répondu Yakov Fain 2009-04-04 14:35:12

beaucoup de microbenchmarks donnés ici ont trouvé des nombres de quelques nanosecondes pour des choses comme les lectures de tableaux/tableaux. C'est tout à fait raisonnable si tout est dans votre cache L1.

un niveau supérieur de cache ou d'accès à la mémoire principale peut avoir des temps d'ordre de grandeur de quelque chose comme 10nS-100nS, vs plus comme 1NS pour le cache L1. Accéder à un ArrayList a une mémoire supplémentaire indirecte, et dans une application réelle, vous pourriez payer ce coût n'importe quoi de presque jamais à chaque temps, selon ce que votre code fait entre les accès. Et, bien sûr, si vous avez beaucoup de petits tableaux, cela pourrait ajouter à votre utilisation de la mémoire et le rendre plus probable, vous aurez des erreurs de cache.

l'affiche originale semble n'en utiliser qu'un et accéder à beaucoup de contenu en peu de temps, donc ce ne devrait pas être une grande difficulté. Mais il peut être différent pour d'autres personnes, et vous devriez faire attention lors de l'interprétation des microbenchmarks.

Java Les chaînes, cependant, sont incroyablement gaspilleuses, surtout si vous en stockez beaucoup de petites (il suffit de les regarder avec un analyseur de mémoire, il semble être > 60 octets pour une chaîne de quelques caractères). Un tableau de cordes a un effet indirect sur L'objet String, et un autre de L'objet String à un char[] qui contient la chaîne elle-même. Si quelque chose va faire exploser votre cache L1, c'est ça, combiné avec des milliers ou des dizaines de milliers de cordes. Donc, si vous êtes sérieux vraiment sérieux au sujet de grattage le plus de performance possible alors vous pourriez envisager de le faire différemment. Vous pourriez dire, maintenir les deux tableaux, un char[] avec toutes les chaînes, l'un après l'autre, et un int[] avec des compensations pour les départs. Ce sera une PITA pour faire quoi que ce soit, et tu n'en as presque certainement pas besoin. Et si vous le faites, vous avez choisi la mauvaise langue.

1
répondu Alex Hayward 2014-10-31 09:59:34

je suis venu ici pour me faire une meilleure idée de l'impact de l'utilisation des listes sur les tableaux. J'ai dû adapter le code ici pour mon scénario: array / list de ~1000 ints en utilisant principalement getters, ce qui signifie array[j] vs. list.get (j)

prendre le meilleur de 7 pour être peu scientifique à ce sujet (les premiers avec la liste où 2,5 x plus lent) je reçois ceci:

array Integer[] best 643ms iterator
ArrayList<Integer> best 1014ms iterator

array Integer[] best 635ms getter
ArrayList<Integer> best 891ms getter (strange though)

- donc, à peu près 30% plus rapide avec le tableau

la deuxième raison pour afficher maintenant, personne ne parle de l'impact si vous faites des codes mathématiques/matrice/simulation/optimisation avec des boucles imbriquées .

dites que vous avez trois niveaux imbriqués et la boucle intérieure est deux fois plus lente que vous regardez 8 fois la performance hit. Quelque chose qui fonctionnerait en une journée prend maintenant une semaine.

* EDIT Tout à fait choqué ici, pour coups de pied j'ai essayé de déclarer int[1000] plutôt que entier [1000]

array int[] best 299ms iterator
array int[] best 296ms getter

à l'Aide de Integer [] vs. int [] représente un double succès de performance, ListArray avec iterator est 3x plus lent que int []. Je pensais vraiment que les implémentations de listes Java étaient similaires aux tableaux natifs...

Code de référence (appeler plusieurs fois):

    public static void testArray()
    {
        final long MAX_ITERATIONS = 1000000;
        final int MAX_LENGTH = 1000;

        Random r = new Random();

        //Integer[] array = new Integer[MAX_LENGTH];
        int[] array = new int[MAX_LENGTH];

        List<Integer> list = new ArrayList<Integer>()
        {{
            for (int i = 0; i < MAX_LENGTH; ++i)
            {
                int val = r.nextInt();
                add(val);
                array[i] = val;
            }
        }};

        long start = System.currentTimeMillis();
        int test_sum = 0;
        for (int i = 0; i < MAX_ITERATIONS; ++i)
        {
//          for (int e : array)
//          for (int e : list)          
            for (int j = 0; j < MAX_LENGTH; ++j)
            {
                int e = array[j];
//              int e = list.get(j);
                test_sum += e;
            }
        }

        long stop = System.currentTimeMillis();

        long ms = (stop - start);
        System.out.println("Time: " + ms);
    }
1
répondu Xult 2018-07-03 14:13:50

Cela dépend de la façon dont vous avez accès.

après le stockage, si vous voulez principalement faire une opération de recherche, avec peu ou pas d'insertion/suppression, puis aller pour le tableau (comme la recherche est faite dans O(1) dans les tableaux, tandis que l'Ajout/Suppression peut avoir besoin de Ré-ordonnancement des éléments).

après le stockage, si votre but principal est d'Ajouter/Supprimer des chaînes, avec peu ou pas d'opération de recherche, puis aller pour la liste.

0
répondu Vikram 2012-07-25 21:53:41

ArrayList utilise intérieurement array object pour ajouter (ou stocker) élément. En d'autres termes, ArrayList est soutenu par des données de tableau -structure.Le tableau de ArrayList est redimensionnable (ou dynamique).

Array est plus rapide que Array parce que ArrayList utilise en interne array. si l'on peut directement ajouter des éléments dans le Tableau et indirectement ajouter un élément dans Tableau à travers ArrayList toujours directement mécanisme est plus rapide que indirectement mécanisme.

il y a deux méthodes add() surchargées dans la classe ArrayList:

1. add(Object) : ajoute un objet à la fin de la liste.

2. add(int index , Object ) : insère l'objet spécifié à la position spécifiée dans la liste.

comment la taille de ArrayList se développe dynamiquement?

public boolean add(E e)        
{       
     ensureCapacity(size+1);
     elementData[size++] = e;         
     return true;
}

le point Important à noter du code ci-dessus est que nous vérifions la capacité de L'ArrayList, avant d'ajouter l'élément. ensureCapacity () détermine quelle est la taille actuelle des éléments occupés et quelle est la taille maximale du tableau. Si la taille des éléments remplis (y compris le nouvel élément à ajouter à la classe ArrayList) est supérieure à la taille maximale du tableau, alors augmentez la taille du tableau. Mais la taille du tableau ne peut pas être augmentée dynamiquement. Donc ce qui se passe en interne est un nouveau tableau créé avec capacité

Jusqu'À La Version 6 De Java

int newCapacity = (oldCapacity * 3)/2 + 1;

(Mise À Jour) De Java 7

 int newCapacity = oldCapacity + (oldCapacity >> 1);

aussi, les données de l'ancien tableau sont copiées dans le nouveau tableau.

ayant des méthodes aériennes dans ArrayList c'est pourquoi Array est plus rapide que ArrayList .

0
répondu Vipin Jain 2016-02-22 06:24:49