arraylist иlist Способы перебора списка в Java




5 Answers

Пример каждого вида, указанного в вопросе:

ListIterationExample.java

import java.util.*;

public class ListIterationExample {

     public static void main(String []args){
        List<Integer> numbers = new ArrayList<Integer>();

        // populates list with initial values
        for (Integer i : Arrays.asList(0,1,2,3,4,5,6,7))
            numbers.add(i);
        printList(numbers);         // 0,1,2,3,4,5,6,7

        // replaces each element with twice its value
        for (int index=0; index < numbers.size(); index++) {
            numbers.set(index, numbers.get(index)*2); 
        }
        printList(numbers);         // 0,2,4,6,8,10,12,14

        // does nothing because list is not being changed
        for (Integer number : numbers) {
            number++; // number = new Integer(number+1);
        }
        printList(numbers);         // 0,2,4,6,8,10,12,14  

        // same as above -- just different syntax
        for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            number++;
        }
        printList(numbers);         // 0,2,4,6,8,10,12,14

        // ListIterator<?> provides an "add" method to insert elements
        // between the current element and the cursor
        for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            iter.add(number+1);     // insert a number right before this
        }
        printList(numbers);         // 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

        // Iterator<?> provides a "remove" method to delete elements
        // between the current element and the cursor
        for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            if (number % 2 == 0)    // if number is even 
                iter.remove();      // remove it from the collection
        }
        printList(numbers);         // 1,3,5,7,9,11,13,15

        // ListIterator<?> provides a "set" method to replace elements
        for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            iter.set(number/2);     // divide each element by 2
        }
        printList(numbers);         // 0,1,2,3,4,5,6,7
     }

     public static void printList(List<Integer> numbers) {
        StringBuilder sb = new StringBuilder();
        for (Integer number : numbers) {
            sb.append(number);
            sb.append(",");
        }
        sb.deleteCharAt(sb.length()-1); // remove trailing comma
        System.out.println(sb.toString());
     }
}
интерфейс list java

Будучи несколько новым для языка Java, я пытаюсь ознакомиться со всеми способами (или, по крайней мере, непатологическими), которые можно перебирать через список (или, возможно, другие коллекции), а также преимущества или недостатки каждого из них.

Учитывая List<E> list , мне известны следующие способы циклического перемещения по всем элементам:

Базовый for loop (конечно, есть эквивалент while / do while )

// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
    E element = list.get(i);
    // 1 - can call methods of element
    // 2 - can use 'i' to make index-based calls to methods of list

    // ...
}

Примечание. Как отметил @amarseillan, эта форма является плохим выбором для итерации над List s, потому что фактическая реализация метода get может быть не такой эффективной, как при использовании Iterator . Например, реализация LinkedList должна пересекать все элементы, предшествующие i, чтобы получить i-й элемент.

В приведенном выше примере реализация List позволяет «сохранить свое место», чтобы повысить эффективность итераций в будущем. Для ArrayList это не имеет большого значения, поскольку сложность / стоимость get - это постоянное время (O (1)), тогда как для LinkedList оно пропорционально размеру списка (O (n)).

Для получения дополнительной информации об вычислительной сложности встроенных реализаций Collections ознакомьтесь с этим вопросом .

Улучшено для цикла (хорошо объяснено в этом вопросе )

for (E element : list) {
    // 1 - can call methods of element

    // ...
}

Iterator

for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
    E element = iter.next();
    // 1 - can call methods of element
    // 2 - can use iter.remove() to remove the current element from the list

    // ...
}

ListIterator

for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
    E element = iter.next();
    // 1 - can call methods of element
    // 2 - can use iter.remove() to remove the current element from the list
    // 3 - can use iter.add(...) to insert a new element into the list
    //     between element and iter->next()
    // 4 - can use iter.set(...) to replace the current element

    // ...
}

Функциональная Java

list.stream().map(e -> e + 1); // Can apply a transformation function for e

Iterable.forEach , Stream.forEach , ...

(Метод карты из API потока Java 8 (см. Ответ @ i_am_zero).)

В классах классов Java 8, которые реализуют Iterable (например, все List s), теперь есть метод forEach , который можно использовать вместо приведенного выше for . (Вот еще один вопрос, который дает хорошее сравнение.)

Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
//     (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
//     being performed with each item.

Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).

Какие существуют другие способы, если они есть?

(Кстати, мой интерес отнюдь не сводится к желанию оптимизировать производительность , я просто хочу знать, какие формы доступны мне как разработчику.)




Итерация в стиле JDK8:

public class IterationDemo {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        list.stream().forEach(elem -> System.out.println("element " + elem));
    }
}



Я не знаю, что вы считаете патологическим, но позвольте мне предоставить некоторые альтернативы, которые вы не могли бы увидеть раньше:

List<E> sl= list ;
while( ! sl.empty() ) {
    E element= sl.get(0) ;
    .....
    sl= sl.subList(1,sl.size());
}

Или его рекурсивная версия:

void visit(List<E> list) {
    if( list.isEmpty() ) return;
    E element= list.get(0) ;
    ....
    visit(list.subList(1,list.size()));
}

Кроме того, рекурсивная версия классической for(int i=0... :

void visit(List<E> list,int pos) {
    if( pos >= list.size() ) return;
    E element= list.get(pos) ;
    ....
    visit(list,pos+1);
}

Я упоминаю их, потому что вы «несколько новы для Java», и это может быть интересно.




Для обратного поиска вы должны использовать следующее:

for (ListIterator<SomeClass> iterator = list.listIterator(list.size()); iterator.hasPrevious();) {
    SomeClass item = iterator.previous();
    ...
    item.remove(); // For instance.
}

Если вы хотите знать позицию, используйте iterator.previousIndex (). Это также помогает написать внутренний цикл, который сравнивает две позиции в списке (итераторы не равны).




Правильно, перечислены многие альтернативы. Самый простой и чистый - это просто использовать расширенный оператор for как показано ниже. Expression имеет некоторый тип, который является итерируемым.

for ( FormalParameter : Expression ) Statement

Например, чтобы перебирать, List <String> ids, мы можем просто так,

for (String str : ids) {
    // Do something
}



Related