Quelle est la bibliothèque de collections Java la plus efficace?
Il y a quelques années, j'ai beaucoup travaillé sur Java et j'avais alors l'impression que trove était la meilleure (la plus efficace) des implémentations Java Collections. Mais quand j'ai lu les réponses à la question " Les bibliothèques libres Java les plus utiles? ", j'ai remarqué que le trésor est à peine mentionné. Alors, quelle est la meilleure bibliothèque de collections Java maintenant?
UPDATE: Pour clarifier, je veux surtout savoir quelle bibliothèque utiliser lorsque je dois stocker des millions d'entrées dans une table de hachage, etc. (besoin d'un petit runtime et empreinte mémoire).
D'après l'inspection, Trove est simplement une bibliothèque de collections pour les types primitifs. Ce n'est pas comme si elle était censée ajouter beaucoup de fonctionnalités aux collections normales du JDK.
Personnellement (et je suis partial) j'aime Goyave (y compris l'ancien Google Java Collections). Il facilite beaucoup diverses tâches (y compris les collections), dans Une méthode au moins raisonnablement efficace: étant donné que les opérations de collecte constituent rarement un goulot d'étranglement dans mon code (selon mon expérience), cela est "meilleur" qu'une API de collecte qui peut être plus efficace, mais ne rend pas mon code aussi lisible.
Étant donné que le chevauchement entre Trove et Guava est quasiment nul, vous pourriez peut-être préciser ce que vous recherchez réellement dans une bibliothèque de collections.
La question concerne (maintenant) le stockage de nombreuses données, qui peuvent être représentées à l'aide de types primitifs tels que int
, dans une carte. Certaines des réponses ici sont très trompeuses à mon avis. Voyons pourquoi.
J'ai modifié le repère de gabarit pour mesurer à la fois la consommation d'exécution et la mémoire. J'ai également ajouté PCJ à ce repère, qui est une autre bibliothèque de collections pour les types primitifs (j'utilise celui-ci de manière extensive). Le test de référence 'officiel' ne compare pas IntIntMaps à Java Collection's _Map<Integer, Integer>
_, en stockant probablement Integers
et stockant ints
n'est pas identique à partir d'un point de vue technique. Mais un utilisateur peut ne pas se soucier de ce détail technique, il veut stocker efficacement les données représentables avec ints
.
D'abord la partie pertinente du code:
_new Operation() {
private long usedMem() {
System.gc();
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
// trove
public void ours() {
long mem = usedMem();
TIntIntHashMap ours = new TIntIntHashMap(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
ours.put(i, i);
}
mem = usedMem() - mem;
System.err.println("trove " + mem + " bytes");
ours.clear();
}
public void pcj() {
long mem = usedMem();
IntKeyIntMap map = new IntKeyIntOpenHashMap(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
map.put(i, i);
}
mem = usedMem() - mem;
System.err.println("pcj " + mem + " bytes");
map.clear();
}
// Java collections
public void theirs() {
long mem = usedMem();
Map<Integer, Integer> map = new HashMap<Integer, Integer>(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
map.put(i, i);
}
mem = usedMem() - mem;
System.err.println("Java " + mem + " bytes");
map.clear();
}
_
Je suppose que les données viennent en tant que primitive ints
, ce qui semble sain. Mais cela implique une pénalité d’exécution pour Java util, en raison de l’auto-boxing, qui n’est pas nécessaire pour les frameworks de collections primitives.
Les résultats d'exécution (sans gc()
appels, bien sûr) sous Windows XP, jdk1.6.0_10:
100000 opérations de vente 100000 contient des opérations Collections Java 1938 ms 203 ms Trace 234 ms 125 ms Pcj 516 ms 94
Bien que cela puisse déjà sembler drastique, ce n’est pas la raison d’utiliser un tel cadre.
La raison est la performance de la mémoire. Les résultats pour une carte contenant 100 000 int
entrées:
Les collections Java oscillent entre 6644536 et 7168840 octets À travers 1853296 octets Pcj 1866112 octets
Les collections Java ont besoin plus de trois fois de la mémoire par rapport aux structures de collection primitives. C'est à dire. vous pouvez conserver trois fois plus de données en mémoire, sans recourir à un disque IO, ce qui diminue les performances d'exécution par magnitudes. Et c'est important. Lisez haute variabilité pour savoir pourquoi.
D'après mon expérience, une consommation de mémoire élevée est le principal problème de performances avec Java, ce qui entraîne bien entendu une dégradation des performances d'exécution. Les cadres de collection primitifs peuvent vraiment aider ici.
Donc: Non, Java.util n'est pas la solution. Et "ajouter des fonctionnalités" à Java collections n'est pas le problème lorsqu'on parle d'efficacité. De plus, les collections JDK modernes ne font pas pas "surpassent même les collections spécialisées de Trove".
Disclaimer: La référence ici est loin d'être complète, ni parfaite. Il est censé faire comprendre le point que j'ai vécu dans de nombreux projets. Les collections primitives sont suffisamment utiles pour tolérer les API fishy - si vous travaillez avec beaucoup de données.
Je sais que c'est un ancien post et il y a une tonne de réponses ici. Mais, les réponses ci-dessus sont superficielles et simplifiées au point de suggérer une bibliothèque. Aucune bibliothèque ne réussit bien entre les différents repères présentés ici. La seule conclusion que je puisse en tirer est que si vous vous souciez de la performance et de la mémoire et que vous vous occupez spécifiquement des types primitifs, il est plus que rentable de regarder les alternatives non-jdk.
Voici une analyse plus solide, en termes de mécanique de référence et de bibliothèques couvertes. This est un sujet dans la liste de développement de Mahout.
Les bibliothèques couvertes sont
Mise à jour juin 2015 : Malheureusement, les critères de référence d'origine ne sont plus disponibles et, en plus, ils sont un peu dépassés. Ici est un benchmark assez récent (Jan 2015) réalisé par quelqu'un d'autre. Il n’est pas aussi complet ni ne contient les outils exploratoires interactifs comme lien original.
Comme d’autres commentateurs l’ont remarqué, la définition du mot "efficace" jette un vaste filet. Cependant, personne n'a encore mentionné la librairie Javolution .
Quelques faits saillants:
La distribution Javolution comprend une suite de tests afin que vous puissiez voir comment ils se comparent à d'autres bibliothèques/collections intégrées.
Quelques bibliothèques de collection à considérer:
Je voudrais avant tout accéder à la bibliothèque de collections JDK. Il couvre la plupart des choses courantes que vous devez faire et est évidemment déjà disponible.
Google Collections est probablement la meilleure bibliothèque de haute qualité en dehors du JDK. C'est très utilisé et bien supporté.
Apache Commons Collections est plus vieux et souffre un peu du problème de "trop de cuisiniers", mais il a aussi beaucoup de choses utiles.
Trove a des collections très spécialisées pour des cas tels que des clés/valeurs primitives. De nos jours, nous constatons que sur les JDK modernes et avec les Java 5+ collections et cas d'utilisation simultanés, les collections JDK dépassent même les collections spécialisées de Trove.
Si vous avez de très nombreux cas d'utilisation simultanée, vous devez absolument consulter des éléments tels que NonBlockingHashMap dans la librairie à grande échelle, qui est une implémentation sans verrouillage et peut écraser ConcurrentHashMap si vous disposez du cas d'utilisation approprié.
Pour stocker des millions de String
sur une carte, consultez http://code.google.com/p/flatmap
Java.util
Désolé pour la réponse évidente, mais pour la plupart des utilisations, les valeurs par défaut Java Collections sont plus que suffisantes.
Je suis développeur de happy-collections from happy-collections sur source-forge
Trove offre quelques avantages.
Cela dit, beaucoup a été fait pour améliorer les collections jdk depuis la création de trove.
Ce sont les stratégies de hachage qui le rendent attrayant pour moi cependant ... Google à vrai dire et lisez leur aperçu.
ConcurrentHashMap ainsi que le Java.util.concurrent
package doit être mentionné, si vous prévoyez d’utiliser HashMap dans plusieurs threads. faible empreinte mémoire est assumé, car cela fait partie de Java standard.
Cela dépend de la façon dont nous définissons le mot "efficace".
Chaque structure de données a son propre comportement Big-Oh pour la lecture, l'écriture, l'itération, l'encombrement de la mémoire, etc. Une liste chaînée dans une bibliothèque est susceptible d'être identique à une autre. Et une carte de hachage sera plus rapide pour la lecture O(1) qu'une liste chaînée O (n).
Mais quand j'ai lu les réponses à la question "Libres les plus utiles Java??"?) ", J'ai remarqué que cet atout est à peine mentionné.
Cela ne sonne pas comme "le plus efficace". Cela me semble "le plus populaire".
Juste quelques commentaires - je n'en ai jamais entendu parler et je ne connais personne qui l'ait utilisé. Les collections intégrées au JDK, à Google ou à Apache Commons sont bien connues de moi.
Si vous souhaitez stocker des millions d'enregistrements dans une table de hachage, il y a de fortes chances que vous rencontriez des problèmes de mémoire. Cela m'est arrivé lorsque j'ai essayé de créer une carte avec 2,3 millions d'objets String, par exemple. Je suis allé avec BerkeleyDB , qui est très mature et fonctionne bien. Ils ont une API Java qui enveloppe l’API Collections, ce qui vous permet de créer facilement des cartes de taille arbitraire avec très peu d’empreinte mémoire. Cependant, l’accès sera plus lent (car il est stocké sur le disque).
Question complémentaire : existe-t-il une bibliothèque décente (et efficace), bien entretenue, pour les collections immuables? Clojure a un excellent support pour cela, et il serait bien d’avoir quelque chose de similaire pour Java.