Написання коду без використання колективних framework було б божевіллям. Це чудова частина Java з безліччю витончених рішень. Що важливіше, на відміну від масивів, тут вам не потрібно дбати про розміри. ArrayList буде зростати доти, доки не закінчиться пам'ять. Розробнику не потрібно турбуватися про початковий розмір і помилку ArrayIndexOutOfBoundsException . Але що якщо поставлена умова стежити за обсягом пам'яті? Чи можемо ми ефективно використовувати пам'ять, працюючи з колекціями?
Виникає стандартне питання: як ініціалізувати список? Нижченаведений код працювати не буде: Це приведе до помилки компіляції: Local variable names не може бути initialized – локальна змінна names може бути неініціалізована. Специфікація Java вимагає, щоб усі локальні змінні (ті, що існують у стеку) були ініціалізовані відповідними значеннями. Ось так це можна зробити: Поза всякими сумнівами, список має бути ініціалізований. Ви можете або створити список у першому ж рядку, або зробити розумніше - використовувати відкладену ( ледачу ) ініціалізацію, як ми зробабо в методі getAllNames()
за замовчуванням створюється список із 10 елементів . Тобто ми сміливо можемо використовувати конструктор за замовчуванням, коли у списку не планується зберігати понад 10 елементів. Що станеться, якщо спробувати додати 11 елемент? Ну, нічого поганого… елемент успішно додасться. Подивіться на метод:
Виникає стандартне питання: як ініціалізувати список? Нижченаведений код працювати не буде: Це приведе до помилки компіляції: Local variable names не може бути initialized – локальна змінна names може бути неініціалізована. Специфікація Java вимагає, щоб усі локальні змінні (ті, що існують у стеку) були ініціалізовані відповідними значеннями. Ось так це можна зробити: Поза всякими сумнівами, список має бути ініціалізований. Ви можете або створити список у першому ж рядку, або зробити розумніше - використовувати відкладену ( ледачу ) ініціалізацію, як ми зробабо в методі getAllNames()
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);
. У такому разі список буде створений лише за потреби - якщо початкові умови не виконані, список ніколи не з'явиться в купі. Тут ми підійшли до головного питання:
який розмір ми повинні задати у списку? Найкращий варіант дати йому точний розмір. Наприклад: У цьому випадку рівно
n імен має бути повернено, і, як наслідок, створюється колекція з елементів
n . Однак, точне значення
n відомо далеко не завжди. Навіть у наведеному прикладі, якщо
n=1000 , а доступно було лише 100 імен? При роботі з колекціями найбільш популярним є виклик конструктора за замовчуванням. Якщо заглянути у вихідний код Java (версії 1.6) Як можна побачити,
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); }
за замовчуванням створюється список із 10 елементів . Тобто ми сміливо можемо використовувати конструктор за замовчуванням, коли у списку не планується зберігати понад 10 елементів. Що станеться, якщо спробувати додати 11 елемент? Ну, нічого поганого… елемент успішно додасться. Подивіться на метод:
public Boolean add(E e) { ensureCapacity(size + 1); //увеличивает modCount!! elementData[size++] = e; return true; }
Розміром масиву керує метод
забезпечення Capacity .
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); } }
Розмір збільшується в 1,5 рази . Створюється новий масив, і елементи переміщуються до нього. Якщо ми задали розмір 10, то на 11 елементі:
- розмір змінюється на 10*3/2 + 1 = 16
- наступне збільшення = 16*3/2 + 1 = 25
- наступне збільшення = 25 * 3 / 2 + 1 = 39 і таке інше.
- Створюйте колекцію тільки тоді, коли її потребуєте , інакше ініціалізуйте null-значенням або використовуйте Collections.EMPTY_LIST .
- Якщо відомий необхідний розмір , вкажіть його в конструкторі колекції.
- Якщо є впевненість, що кількість елементів не перевищить 10 , вільно використовуйте конструктор за замовчуванням.
- Ризик, пов'язаний зі створенням колекції нульового розміру , полягає в тому, що частота створення нових масивів та копіювання даних може бути вищою. Потрібно дуже ретельно продумати, чи висока вигода від використання колекцій нульового розміру .
- Якщо ініціалізували колекцію надто великого розміру на початку методу і хочеться зменшити його, є метод trimToSize() .
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ