JavaRush /Java Blog /Random-IT /new ArrayList(????) come e dove è meglio inizializzare
Vovan
Livello 22

new ArrayList(????) come e dove è meglio inizializzare

Pubblicato nel gruppo Random-IT
Scrivere codice senza utilizzare il framework delle raccolte sarebbe pazzesco. Questo è un meraviglioso pezzo di Java con molte soluzioni ordinate. Ancora più importante, a differenza degli array, non devi preoccuparti delle dimensioni. L'ArrayList crescerà finché non esaurirà la memoria. Lo sviluppatore non deve preoccuparsi della dimensione iniziale e dell'errore ArrayIndexOutOfBoundsException . Ma cosa succede se esiste una condizione per monitorare la quantità di memoria? Possiamo utilizzare la memoria in modo efficiente quando lavoriamo con le raccolte?
Sorge una domanda standard: come inizializzare un elenco? Il codice seguente non funzionerà: Risulterà in un errore di compilazione: I nomi delle variabili locali potrebbero non essere stati inizializzati . La specifica Java richiede che tutte le variabili locali (quelle presenti nello stack) siano inizializzate con valori appropriati. Ecco come puoi farlo: Senza dubbio, l'elenco deve essere inizializzato. Puoi creare l'elenco sulla prima riga oppure puoi fare qualcosa di più intelligente e utilizzare l'inizializzazione pigra come abbiamo fatto nel metodo getAllNames() . In questo caso l'elenco verrà creato solo quando necessario: se le condizioni iniziali non vengono soddisfatte, l'elenco non verrà mai visualizzato nell'heap. Qui arriviamo alla domanda principale: quale dimensione dobbiamo impostare per la lista? L'opzione migliore è dargli la dimensione esatta. Ad esempio: In questo caso devono essere restituiti esattamente n nomi e di conseguenza viene creata una raccolta di n elementi. Tuttavia, il valore esatto di n non è sempre noto. Anche nell'esempio fornito, cosa accadrebbe se n=1000 e ci fossero solo 100 nomi disponibili? Quando si lavora con le raccolte, il metodo più diffuso è chiamare il costruttore predefinito. Se guardi il codice sorgente Java (versione 1.6) Come puoi vedere, per impostazione predefinita viene creata una lista di 10 elementi . Cioè, possiamo tranquillamente utilizzare il costruttore predefinito quando non prevediamo di memorizzare più di 10 elementi nell'elenco. Cosa succede se provi ad aggiungere l'undicesimo elemento? Beh, niente di male... l'elemento verrà aggiunto con successo. Guarda il metodo: la dimensione dell'array è controllata dal metodo verifyCapacity . La dimensione aumenta di 1,5 volte . Viene creato un nuovo array e gli elementi vengono spostati al suo interno. Se impostiamo la dimensione su 10, quindi sull'undicesimo elemento:
public List getAllNames() { List names; if (/*необходимые условия выполнены*/) { names = new ArrayList (); /*заполнение списка*/ } return names; }
List names = null; List names = new ArrayList (); List names = new ArrayList (0); List names = new ArrayList (size);
public List getTopNames (int n) { List names = null; if ( /*необходимые условия выполнены*/) { names = new ArrayList (n); /*заполнение списка*/ } return names; }
names = new ArrayList ();

/** * Конструирует пустой список с указанной начальной емкостью. * * @param initialCapacity начальная емкость списка * @exception IllegalArgumentException если указанная начальная емкость отрицательна * */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) this.elementData = new Object[initialCapacity]; } /** * Конструирует пустой список с начальной емкостью, равной 10. */ public ArrayList() { this(10); }
public Boolean add(E e) { ensureCapacity(size + 1); //увеличивает modCount!! elementData[size++] = e; return true; } public void ensureCapacity (int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { throw new IllegalArgumentException(“Illegal Capacity: ” + initialCapacity); Object oldData[] = elementData; int newCapacity = (oldCapacity * 3) / 2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity обычно ближе к размеру, так что это беспроигрышно: elementData = Arrays.copyOf(elementData, newCapacity); } }
  • la dimensione cambia in 10 * 3 / 2 + 1 = 16
  • aumento successivo = 16 * 3 / 2 + 1 = 25
  • aumento successivo = 25 * 3 / 2 + 1 = 39 e così via.
In caso di 100 elementi, la JVM dovrà creare più volte un nuovo array e copiarvi gli elementi. Tenendo conto di ciò, se si presume la dimensione richiesta dell'array, è meglio impostare la capacità iniziale su un valore vicino ad essa. Ecco alcune linee guida per l’azione:
  1. Crea una raccolta solo quando ne hai bisogno , altrimenti inizializzala su null o utilizza Collections.EMPTY_LIST .
  2. Se conosci la dimensione esatta richiesta , specificala nel costruttore della raccolta.
  3. Se sei sicuro che il numero di elementi non supererà 10 , sentiti libero di utilizzare il costruttore predefinito.
  4. Il rischio associato alla creazione di una raccolta di dimensione zero è che la frequenza di creazione di nuovi array e di copia dei dati potrebbe essere più elevata. È necessario riflettere molto attentamente se il vantaggio derivante dall'utilizzo di raccolte a dimensione zero è davvero così grande .
  5. Se hai inizializzato una raccolta troppo grande all'inizio del metodo e vuoi ridurla, esiste il metodo trimToSize() .
Naturalmente, queste linee guida si applicano quando si lavora con raccolte basate su array e nulla di tutto ciò ha senso nel caso di un elenco collegato. In effetti, è improbabile che questi problemi uccidano il programma, ma se c'è un'opportunità per fare un po' meglio, perché non usarla. Hai altri consigli utili? Hai trovato modi per far funzionare meglio le cose? Oppure tutto questo è inutile? Cosa ne pensi?
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION