2010-05-09 7 views
5

J'ai un problème avec ArrayList. J'en ai besoin pour stocker un résultat. Parce que je veux commencer avec l'élément n j'ai essayé de donner ArrayList une capacité avec ensureCapacity(n+1) pour utiliser set(n,x) mais je reçois un IndexOutOfBoundsException.Java ArrayList <Double> IndexOutOfBoundsException Problème

J'ai essayé de stocker n add(x) avant l'utilisation de l'ensemble et cela fonctionne.

Je voudrais donc savoir pourquoi il ne fonctionne pas sur mon chemin et comment résoudre cela parce que mettre n fois add(x) est pas un bon style ;-)

Répondre

6

Si vous ne souhaitez pas utiliser votre propre boucle et la liste méthode add directement alors il y a une autre façon. Créez votre ArrayList avec le nombre d'éléments que vous voulez directement comme ceci:

final int MAX_ELEMENTS = 1000; 
List<Integer> myList = new ArrayList<Integer>(
    Collections.<Integer>nCopies(MAX_ELEMENTS, null)); 

Ou, si vous avez déjà une liste que vous souhaitez étendre la taille par n éléments:

myList.addAll(Collections.<Integer>nCopies(n, null)); 

(Note, j'ai supposé ici que la liste contiendrait Integer objets, mais vous pouvez changer cela en votre type personnalisé. Si vous travaillez avec des types raw/pre-Java 5, supprimez simplement les déclarations génériques.)

En ce qui concerne votre question actuelle: capacité! = Contenu. Une ArrayList possède à la fois un tableau physique et un compte de ce qui s'y trouve réellement. Augmenter la capacité, modifie le tableau interne afin qu'il puisse contenir de nombreux éléments, cependant, le nombre ne change pas. Vous devez ajouter des éléments pour augmenter ce nombre.

D'autre part, si vous essayez simplement de définir des éléments spécifiques et de connaître le maximum que vous voulez utiliser, pourquoi ne pas utiliser un tableau directement? Si vous devez ensuite transmettre ce tableau à une API prenant List s, utilisez Arrays.asList. Les autres classes pourraient encore changer le contenu de votre tableau de sauvegarde, mais il ne serait pas en mesure d'augmenter la taille ou la capacité de celui-ci.

7

Lorsque vous modifiez la capacité de une ArrayList ne crée aucun élément, elle réserve juste de la mémoire là où il pourrait y avoir des éléments. Vous pouvez vérifier la taille avant et après avoir ajusté la capacité et vous verrez qu'elle ne change pas. Le but de la modification de la capacité est de savoir si vous savez à l'avance combien d'éléments vous aurez, vous éviterez ainsi des redimensionnements inutiles à mesure que vous ajoutez de nouveaux éléments et vous éviterez le gaspillage de mémoire dû à la capacité inutilisée.

0

Vous obtenez cette exception parce ensureCapacity() vérifie simplement qu'il ya suffisamment de mémoire est allouée pour ajouter des objets à un ArrayList, je crois que cela est dans le cas où vous souhaitez ajouter plusieurs objets à la fois, sans avoir à déménager Mémoire.

Pour faire ce que vous voulez vous devez lancer le ArrayList avec des éléments nuls premiers ...

int n = 10; //capacity required 
ArrayList foo = new ArrayList(); 

for(int i=0; i<=n; i++) { 
     foo.add(null); 
} 

Ensuite, vous avez des objets dans la liste que vous pouvez faire référence via l'index et vous recevez l'habitude de l'exception.

0

ensureCapacity() a un autre but. Il devrait être utilisé dans les cas où vous connaissez la taille requise du List après qu'il a été construit. Si vous connaissez la taille avant qu'il ne soit constructeur, transmettez-le simplement en tant qu'argument au constructeur.

Dans le premier cas, utilisez ensureCapacity() pour enregistrer plusieurs copies de la matrice de support sur chaque ajout. Cependant, en utilisant cette méthode laisse la structure dans un état apparemment incompatible

  • la taille de la matrice de support est augmentée
  • le domaine size sur le ArrayList est pas.

Ceci, cependant, est normal, puisque la capacité = taille

Utilisez la méthode add(..), qui est la seule qui augmente le champ size:

ArrayList list = new ArrayList(); 
list.ensureCapacity(5); // this can be done with constructing new ArrayList(5) 

for (int i = 0; i < list.size - 1; i ++) { 
    list.add(null); 
} 
list.add(yourObject); 
0

Peut-être vous devriez repenser le choix d'utiliser List<Double>. Il se peut qu'un Map<Integer,Double> soit plus approprié si des éléments doivent être ajoutés dans un ordre impair.

Si cela est approprié dépend de connaissances sur votre utilisation que je n'ai pas pour le moment cependant.

La structure de données va-t-elle éventuellement être complètement remplie ou les données sont-elles éparses?

+0

Ce serait la solution la plus propre, mais ArrayList est utilisé comme argument dans une méthode qui ne prend que ArrayList. Peut-être que si j'ai assez de temps je vais le surcharger pour utiliser Map insted. –

+1

Vous pouvez également envisager de charger une carte, puis d'écrire une méthode pour créer une ArrayList à partir du contenu de la carte après son chargement. Mais si vous avez vraiment besoin d'un ArrayList, la solution affichée par Bozho pourrait être très bien. –

+0

"ArrayList est utilisé comme argument dans une méthode qui ne prend que ArrayList" Sérieusement? Il y a du code là-bas qui prend 'ArrayList' plutôt que simplement' List'? – Powerlord

0

ce que les autres ont dit au sujet ensureCapacity() ...

vous devez écrire une classe comme DynamicArrayList étend ArrayList. alors il suffit de surcharger add (n, x) pour faire avec la boucle pour ajouter (null) la logique spécifiée à propos de.

2

Comme d'autres l'ont indiqué, ensureCapacity() est juste lié à la performance, n'est pas fréquemment utilisé par l'utilisateur commun.

de la pensée de Bruce Eckel dans le livre Java:

Dans un message privé, Joshua Bloch a écrit: » ... Je crois que nous nous sommes trompés par permettant les détails de mise en œuvre (par exemple comme table de hachage la taille et le facteur de charge) dans nos API. le client doit peut-être nous dire la taille maximale prévue d'une collection, et nous devrions à partir de là. les clients peuvent facilement faire plus de mal que de bien en choisissant valeurs pour ces paramètres. Comme un exemple extrême , envisager Vector capacityIncrement. Personne ne devrait jamais définir cela, et nous ne devrions pas avoir à condition que cela. Si vous le définissez à une valeur non nulle , le coût asymptotique de une séquence d'ajouts passe de linéaire à quadratique. En d'autres termes, il détruit votre performance. Au fil du temps, nous commençons à sagement au sujet de ce genre de chose. Si vous regardez IdentityHashMap, vous verrez qu'il n'a pas de paramètres de réglage à faible niveau »