JavaRush /Java блог /Random UA /new ArrayList(????) як і де краще ініціалізувати
Vovan
22 рівень

new ArrayList(????) як і де краще ініціалізувати

Стаття з групи Random UA
Написання коду без використання колективних framework було б божевіллям. Це чудова частина Java з безліччю витончених рішень. Що важливіше, на відміну від масивів, тут вам не потрібно дбати про розміри. ArrayList буде зростати доти, доки не закінчиться пам'ять. Розробнику не потрібно турбуватися про початковий розмір і помилку ArrayIndexOutOfBoundsException . Але що якщо поставлена ​​умова стежити за обсягом пам'яті? Чи можемо ми ефективно використовувати пам'ять, працюючи з колекціями?
Виникає стандартне питання: як ініціалізувати список? Нижченаведений код працювати не буде: Це приведе до помилки компіляції: 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 і таке інше.
У разі 100 елементів, JVM необхідно буде кілька разів створювати новий масив і копіювати елементи. З огляду на це, якщо є припущення про необхідний розмір масиву, краще задавати початкову ємність близькою до нього. Ось кілька вказівок до дії:
  1. Створюйте колекцію тільки тоді, коли її потребуєте , інакше ініціалізуйте null-значенням або використовуйте Collections.EMPTY_LIST .
  2. Якщо відомий необхідний розмір , вкажіть його в конструкторі колекції.
  3. Якщо є впевненість, що кількість елементів не перевищить 10 , вільно використовуйте конструктор за замовчуванням.
  4. Ризик, пов'язаний зі створенням колекції нульового розміру , полягає в тому, що частота створення нових масивів та копіювання даних може бути вищою. Потрібно дуже ретельно продумати, чи висока вигода від використання колекцій нульового розміру .
  5. Якщо ініціалізували колекцію надто великого розміру на початку методу і хочеться зменшити його, є метод trimToSize() .
Звичайно, ці вказівки застосовні при роботі з колекціями на основі масиву, і все це не має сенсу у зв'язковому списку. Насправді ці проблеми навряд чи будуть убивцями програми, але якщо є можливість зробити трохи краще, чому б її не використовувати. Чи є у вас інші корисні вказівки? Знайдені вами способи змусити речі працювати краще? Чи це все зайве? Що ви думаєте? Оригінал статті тут.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ