Java: найкращий спосіб повторити колекцію (тут ArrayList)


98

Сьогодні я із задоволенням кодував далеко, коли потрапив до фрагмента коду, який я вже використовував сотні разів:

Ітерація через колекцію (тут ArrayList)

Я чомусь переглянув параметри автоматичного завершення Eclipse, і мені стало цікаво:

У яких випадках краще використовувати наступні петлі, ніж інші?

Класичний цикл індексу масиву:

for (int i = 0; i < collection.length; i++) {
  type array_element = collection.get(index);
}

Ітератор має наступний () / наступний ():

for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
  type type = (type) iterator.next();   
}

І мій улюблений, тому що його так просто написати:

for (iterable_type iterable_element : collection) {

}

2
Коли мова йде про мене, я в основному використовую 3-ю петлю.
— Гаррі Радість

1
Для другого способу його краще використовувати:for (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
— Майк Джонс

4
Інтерфейс колекції не містить методу "отримати", тому перший не завжди можливий.
— ThePerson

Відповіді:


104

Перший корисний, коли вам також потрібен індекс елемента. Це в основному еквівалентно двом іншим варіантам для ArrayLists, але буде дуже повільним, якщо ви використовуєте a LinkedList.

Другий корисний, коли вам не потрібен індекс елемента, але, можливо, потрібно буде видалити елементи під час ітерації. Але це має недолік - бути занадто багатослівним ІМО.

Третя версія також є моїм бажаним вибором. Він короткий і працює для всіх випадків, коли вам не потрібні індекси або базовий ітератор (тобто ви лише отримуєте доступ до елементів, не видаляючи їх або Collectionжодним чином не змінюючи - що є найпоширенішим випадком).


3
+1 Побий мене до цього. збирався згадати LinkedList (не всі Collection дешеві для пошуку за індексом).
— The Scrum Meister

Поки потрібні просто циклічні елементи, завжди добре використовувати 3-ю версію, оскільки реалізація вже існує для всіх різних колекцій, а Sun або будь-яка реалізація JDK прагне покращити продуктивність, а не кожну.
— Фані

@Phani: Інші два варіанти також працюють на будь-якій реалізації JDK.
— МАК

Я не казав, що це не спрацює, але якщо випадково внести певні покращення чи зміни продуктивності для реалізації колекцій, то це автоматично застосує ваш код і вам не потрібно писати для підвищення продуктивності це те, що я маю на увазі.
— Фані

1
@ Фані: AFAIK 3-а форма - це просто синтаксичний цукор для 2-ї форми (тобто під кришкою варіант foreach використовує ітератор). Тому будь-які переваги від продуктивності повинні бути доступні для обох варіантів. Перша версія звичайно не отримає жодних переваг від продуктивності (наприклад, якщоList реалізовано як дерево, воно насправді буде повільніше).
— МАК

36

Усі вони мають власні потреби:

  1. Якщо у вас є ітерабельний і вам потрібно беззастережно переходити до них усіх:

    для (iterable_type iterable_element: collection)

  2. Якщо у вас є ітерабельний, але вам потрібно умовно перейти:

    для (Iterator iterator = collection.iterator (); iterator.hasNext ();)

  3. Якщо структура даних не реалізує ітерабельно:

    for (int i = 0; i <collection.length; i ++)


Чи можете ви це зробити, щоб перемогти перший метод умовно: якщо (iterable_element.some_attribute) {// зробити щось; } else {// нічого не робити; }. Якщо так, то по суті немає різниці між першим та другим методом, крім синтаксичного цукру.
— Томас Нгуен

1 настільки ж здатний умовно перейти, як інші, які використовують breakта / абоcontinue
— arcyqwerty

13

Додатково використовується утиліта stream () колекцій з Java 8

collection.forEach((temp) -> {
            System.out.println(temp);
});

або

collection.forEach(System.out::println);

Більш детальна інформація про Java 8 потоку і колекціям для wonderers посилання


4

Жоден з них не "кращий", ніж інші. Третє, для мене, читабельніше, але для того, хто не використовує передбачень, це може виглядати дивно (вони можуть віддати перевагу першому). Усі 3 досить зрозумілі для всіх, хто розуміє Java, тому вибирайте те, що робить вас краще щодо коду.

Перший - найосновніший, тому це найбільш універсальний зразок (працює для масивів, усіх ітерабелів, які я можу придумати). Це єдина різниця, яку я можу придумати. У більш складних випадках (наприклад, вам потрібно мати доступ до поточного індексу або вам потрібно відфільтрувати список), перший і другий випадки можуть мати більше сенсу відповідно. Для простого випадку (ітерабельний об'єкт, особливих вимог немає) третій видається найчистішим.


2

Перший варіант - краща ефективність роботи (Як ArrayList реалізує інтерфейс RandomAccess). Відповідно до java doc, реалізація списку повинна реалізовувати інтерфейс RandomAccess, якщо для типових примірників класу цей цикл:

 for (int i=0, n=list.size(); i < n; i++)
     list.get(i);

працює швидше, ніж цей цикл:

 for (Iterator i=list.iterator(); i.hasNext(); )
     i.next();

Я сподіваюся, що це допомагає. Перший варіант буде повільним для списків послідовного доступу.


1

Ось приклад

Query query = em.createQuery("from Student");
             java.util.List list = query.getResultList();
             for (int i = 0; i < list.size(); i++) 
             {

                 student = (Student) list.get(i);
                 System.out.println(student.id  + "  " + student.age + " " + student.name + " " + student.prenom);

             }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.