386 votes

Matrice ou liste en Java. Qui est plus rapide ?

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

Étant donné que les tableaux de conservent toutes les données dans un bloc contigu de mémoire (contrairement aux listes), l’utilisation d’un tableau pour stocker des milliers de chaînes causerait des problèmes ?

Réponse : Le consensus commun est que la différence de performance est mineure. Interface de la liste offre davantage de flexibilité.

394voto

Fortyrunner Points 8072

Je suggère que vous utilisez un profileur pour tester ce qui est plus rapide.

Mon opinion personnelle est que vous devez utiliser des listes.

Je travaille sur une grande base de code et un précédent groupe de développeurs a utilisé les tableaux partout. Il a fait le code très rigide. Après avoir changé de gros morceaux de celui-ci aux listes, nous avons ne remarqué aucune différence dans la vitesse.

175voto

cygil Points 2076

La Java façon est que vous devriez considérer ce que les données de l'abstraction correspond le mieux à vos besoins. Rappelez-vous qu'en Java, une Liste est un résumé, pas un type concret. Vous devez déclarer les cordes comme une Liste, puis l'initialiser à l'aide de la liste de tableaux mise en œuvre.

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

Cette séparation de Type Abstrait de Données et de mise en œuvre spécifiques est l'un des principaux aspects de la programmation orientée objet.

Une liste de tableaux met en œuvre la Liste Type Abstrait de Données à l'aide d'un tableau comme son implémentation sous-jacente. La vitesse d'accès est pratiquement identique à un tableau, avec les avantages supplémentaires d'être en mesure d'ajouter et de soustraire des éléments d'une Liste (bien que ce soit un O(n) opérations avec une liste de tableaux), et que si vous décidez de changer l'implémentation sous-jacente plus tard, vous pouvez. Par exemple, si vous réalisez que vous avez besoin accès synchronisé, vous pouvez changer la mise en œuvre d'un Vecteur sans avoir à réécrire tout le code.

En fait, la liste de tableaux a été spécifiquement conçu pour remplacer le faible niveau de la matrice de construire dans la plupart des contextes. Si Java a été conçu aujourd'hui, il est tout à fait possible que des tableaux ont été laissés de côté complètement en faveur de la liste de tableaux de construire.

Depuis les tableaux de conserver toutes les données dans un espace contigu de mémoire (à la différence des Listes), l'utilisation d'un tableau pour stocker des milliers de chaînes de causer 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 deux tableaux et ArrayList va stocker quelques milliers de références dans une ligne de tableau, de sorte qu'ils sont essentiellement identiques. Vous pouvez considérer qu'un bloc contigu de quelques milliers de 32 bits références seront toujours facilement disponibles sur le matériel moderne. Cela ne garantit pas que vous ne manquerez pas de mémoire tout à fait, bien sûr, c'est juste que le bloc contigu de mémoire exigence n'est pas difficile à accomplir.

125voto

assylias Points 102015

Bien que les réponses qui propose d'utiliser ArrayList n'a de sens que dans la plupart scénario, la question réelle de la performance relative n'a pas vraiment eu de réponse.

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

  • créer
  • définir un élément
  • un élément
  • clone/copier

Conclusion générale

Bien que les opérations get et set sont un peu plus lent sur une liste de tableaux (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 petites choses à garder à l'esprit:

  • les opérations de redimensionnement sur une liste (lors de l'appel d' list.add(...)) sont coûteux et que l'on devrait essayer de définir la capacité initiale à un niveau adéquat lorsque c'est possible (à noter que le même problème se pose lors de l'utilisation d'un tableau)
  • lorsque vous traitez avec les primitives, les tableaux peuvent être beaucoup plus rapides car ils permettent d'éviter de nombreux boxing/unboxing conversions
  • une demande à laquelle il n'obtient ou définit des valeurs dans une liste de tableaux (pas très commun!!!) pourrait voir un gain de performance de plus de 25% en passant à un tableau

Les résultats détaillés

Voici les résultats que j'ai mesuré pour ces trois opérations à l'aide de la jmh l'analyse comparative de la bibliothèque de fois (en nanosecondes) avec JDK 7 sur un x86 standard machine de bureau. Notez que la liste de tableaux ne sont jamais redimensionnées dans les tests afin de vérifier que les résultats sont comparables. Référence code disponible ici.

Tableau/Liste De Tableaux De La Création

J'ai couru 4 tests, d'exécuter les commandes suivantes:

  • 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.

obtenez des opérations

J'ai couru 2 tests, d'exécuter les commandes suivantes:

  • 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: arriver à partir d'un tableau est d'environ 25% plus rapide que d'obtenir à partir d'une liste de tableaux, bien que la différence n'est que de l'ordre de l'ordre de la nanoseconde.

ensemble des opérations

J'ai couru 2 tests, d'exécuter les commandes suivantes:

  • 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: définir les opérations sur les tableaux sont environ 40% plus rapide que sur les listes, mais que, pour l'obtenir, chaque ensemble de l'opération ne prend que quelques nanosecondes - donc pour la différence pour atteindre 1 seconde, il serait nécessaire de définir les éléments de la liste/tableau des centaines de millions de fois!

clone/copie

Liste de tableaux du constructeur de copie délégués Arrays.copyOf le rendement est identique à la matrice de copie (copie d'un tableau via clone, Arrays.copyOf ou System.arrayCopy fait pas de différence en terme de performance).

108voto

JesperE Points 34356

Vous devriez préférer les types génériques sur des tableaux. Comme mentionné par d'autres, les tableaux sont rigides et n'ont pas le pouvoir expressif des types génériques. (Il y a toutefois un support d'exécution typage, 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:

  • N'optimisent pas jusqu'à ce que vous avez une belle, propre, et de travail de la version de votre code. Changer de types génériques pourrait très bien être motivé lors de cette étape, déjà.
  • Lorsque vous avez une version qui est agréable et propre, décider s'il est assez rapide.
  • Si elle n'est pas assez rapide, la mesure de sa performance. Cette étape est importante pour deux raisons. Si vous ne mesurez pas, vous n'aurez pas (1) de connaître l'impact de toutes les optimisations que vous faites et (2) de savoir où les optimiser.
  • Optimiser la partie la plus chaude de votre code.
  • Mesurer à nouveau. C'est tout aussi important que la mesure de avant de. Si l'optimisation n'est pas pas d'améliorer les choses, de revenir. Rappelez-vous, le code sans l'optimisation était propre, agréable, et de travail.

24voto

J'imagine que l'affiche originale est à venir à partir d'un C++/STL en arrière-plan qui est à l'origine d'une certaine confusion. En C++ std::list est une liste doublement chaînée.

En Java, [java.util.]List est une implémentation libre de l'interface (abstraite pure classe en C++). List peut être une liste doublement chaînée - java.util.LinkedList est prévue. Cependant, 99 fois sur 100 quand vous voulez un new List, vous souhaitez utiliser java.util.ArrayList au lieu de cela, ce qui est l'équivalent de C++ std::vector. Il existe d'autres implémentations standard, tels que ceux rendements en java.util.Collections.emptyList et java.util.Arrays.asList.

À partir d'une performance au point il y a un très petit coup de passer par l'intermédiaire d'une interface et d'un objet supplémentaire, cependant runtime inline signifie rarement, et a une signification. Rappelez-vous aussi que String sont (généralement) un objet plus le 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 un pointeur en tant que tel, les tableaux de caractères forment un objet en chaîne de caractères (et elles ne seront pas généralement être partagé).

Si ce code est très sensible aux performances, vous pouvez créer un seul char[] tableau (ou même byte[]) pour tous les caractères de toutes les chaînes, et ensuite un tableau des décalages. Autant que je me souvienne, c'est comment javac est mis en œuvre.

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