2010-05-09 15 views
5

Ho un problema con ArrayList. Ne ho bisogno per memorizzare un risultato. Perché voglio iniziare con l'elemento n Ho provato a dare alla capacità ArrayList con ensureCapacity(n+1) per utilizzare set(n,x) ma ottengo uno IndexOutOfBoundsException.Java ArrayList <Double> IndexOutOfBoundsException Problem

Ho provato a memorizzare n add(x) prima dell'uso di set e questo funziona.

così mi piacerebbe sapere perché non funziona per la mia strada e come risolvere questo perché i tempi put n un add(x) non è un buon stile ;-)

risposta

6

Se non vi piace utilizzando il proprio ciclo e il metodo lista add direttamente poi c'è un altro modo. Crea il tuo ArrayList con il numero di elementi che si desidera direttamente in questo modo:

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

Oppure, se si dispone già di una lista che si desidera espandere la dimensione da n elementi:

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

(Nota, ho presunto qui che l'elenco sarebbe in possesso di oggetti Integer, ma è possibile modificare questo al tipo personalizzato. Se lavori con i tipi raw/pre-Java 5, rilascia le dichiarazioni generiche.)

Come per la tua domanda attuale: capacità! = Contenuto. Un ArrayList internamente ha sia una matrice fisica che un conteggio di ciò che è effettivamente contenuto. Aumentando la capacità, cambia l'array interno in modo che possa contenere molti elementi, tuttavia il conteggio non cambia. È necessario aggiungere elementi per aumentare tale conteggio.

D'altra parte, se si sta solo cercando di impostare elementi specifici e conoscere il massimo che si desidera utilizzare, perché non utilizzare direttamente un array? Se è quindi necessario passare questo array a un'API che impiega List s, utilizzare Arrays.asList. Le altre classi potrebbero comunque modificare il contenuto dell'array di backup, ma non sarebbe in grado di aumentarne le dimensioni o la capacità.

7

Quando si modifica la capacità di un ArrayList non crea alcun elemento, ma semplicemente riserva memoria dove potrebbero esserci elementi. Puoi controllare le dimensioni prima e dopo aver regolato la capacità e vedrai che non cambia.

Lo scopo di modificare la capacità è se si conoscono in anticipo quanti elementi si avranno, quindi è possibile evitare ridimensionamenti ripetuti non necessari quando si aggiungono nuovi elementi ed è possibile evitare lo spreco di memoria dalla capacità inutilizzata in eccesso.

0

Hai trovato questa eccezione perché ensureCapacity() fa solo in modo che ci sia abbastanza memoria allocata per l'aggiunta di oggetti a un ArrayList, credo che questo sia nel caso in cui si desidera aggiungere più oggetti contemporaneamente, senza dover riposizionare memoria.

Per fare ciò che si desidera si dovrà avviare l'ArrayList con elementi nulli primi ...

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

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

Poi si hanno oggetti nella lista che si può fare riferimento tramite indice e voi non ricevere l'eccezione.

0

ensureCapacity() ha un altro scopo. Dovrebbe essere usato nei casi in cui si viene a conoscenza della dimensione richiesta dello List dopo la sua costruzione. Se si conosce la dimensione prima che sia costruttore, basta passarla come argomento al costruttore.

Nel primo caso utilizzare ensureCapacity() per salvare più copie del backing array su ciascuna aggiunta. Tuttavia, utilizzando tale metodo lascia la struttura in uno stato apparentemente incoerente

  • la dimensione della matrice di supporto viene aumentata
  • campo size sul ArrayList non è.

Questo, tuttavia, è normale, dal momento che la capacità = dimensione

Utilizzare il metodo add(..), che è l'unico che è in aumento il campo 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

Forse dovresti riconsiderare la scelta dell'uso di List<Double>. Potrebbe essere che uno Map<Integer,Double> sarebbe più appropriato se gli elementi devono essere aggiunti in un ordine dispari.

Se questo è appropriato dipende dalla conoscenza del tuo utilizzo che non ho al momento però.

La struttura dei dati può essere completata completamente oppure i dati sono sparsi?

+0

Questa sarebbe la soluzione più pulita ma ArrayList viene utilizzato come argomento in un metodo che richiede solo ArrayList. Forse se ho abbastanza tempo lo sovraccarico per l'utilizzo di Map insted. –

+1

Si potrebbe anche prendere in considerazione il caricamento di una mappa e quindi scrivere un metodo per creare un ArrayList dal contenuto della mappa dopo il caricamento. Ma se hai davvero bisogno di un ArrayList, la soluzione postata da Bozho potrebbe andar bene. –

+0

"l'ArrayList viene utilizzato come argomento in un metodo che richiede solo ArrayList" Seriamente? C'è del codice là fuori che richiede 'ArrayList' piuttosto che' List'? – Powerlord

0

quello che gli altri hanno detto circa ensureCapacity() ...

si dovrebbe scrivere una classe come DynamicArrayList estende ArrayList. quindi basta sovrascrivere add (n, x) con la logica for add loop (null) specificata.

2

Come altri hanno risposto, ensureCapacity() è solo relativo alle prestazioni, non viene utilizzato frequentemente dall'utente comune.

Da pensiero di Bruce Eckel in Java libro:

In un messaggio privato, Joshua Bloch ha scritto:" ... Credo che abbiamo sbagliato con consentendo dettagli di implementazione (come come tabella hash dimensioni e fattore di carico) nelle nostre API Il cliente dovrebbe forse dirci la dimensione massima prevista di di una raccolta, e noi dovremmo prendere da lì. I clienti possono facilmente fare più male che bene scegliendo valori per questi parametri. Come esempio estremo , prendere in considerazione la capacità di Vector capacityIncrement. Nessuno dovrebbe mai impostare e non dovrebbe essere fornito da . Se lo si imposta su un valore diverso da zero , il costo asintotico di una sequenza di accodamenti va da quadrata a lineare. In altre parole, lo distrugge la tua performance. Con il passare del tempo, stiamo iniziando a saggiarci su questo tipo di cose . Se si guarda alla IdentityHashMap, vedrete che essa non ci sono di basso livello parametri di regolazione"