Foreach list array java

Ways to iterate over a list in Java

Being somewhat new to the Java language I’m trying to familiarize myself with all the ways (or at least the non-pathological ones) that one might iterate through a list (or perhaps other collections) and the advantages or disadvantages of each. Given a List list object, I know of the following ways to loop through all elements:

Basic for loop (of course, there’re equivalent while / do while loops as well)

// 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 // . >

Note: As @amarseillan pointed out, this form is a poor choice for iterating over List s, because the actual implementation of the get method may not be as efficient as when using an Iterator . For example, LinkedList implementations must traverse all of the elements preceding i to get the i-th element. In the above example there’s no way for the List implementation to «save its place» to make future iterations more efficient. For an ArrayList it doesn’t really matter, because the complexity/cost of get is constant time (O(1)) whereas for a LinkedList is it proportional to the size of the list (O(n)). For more information about the computational complexity of the built-in Collections implementations, check out this question.

Читайте также:  background-position

Enhanced for loop (nicely explained in this question)

Iterator

for (Iterator 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 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 // . > 

Functional Java

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

Iterable.forEach, Stream.forEach, .

(A map method from Java 8’s Stream API (see @i_am_zero’s answer).) In Java 8 collection classes that implement Iterable (for example, all List s) now have a forEach method, which can be used instead of the for loop statement demonstrated above. (Here is another question that provides a good comparison.)

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). 

What other ways are there, if any? (BTW, my interest does not stem at all from a desire to optimize performance; I just want to know what forms are available to me as a developer.)

Those are the non-pathological ones, although you might also use any of several functional-style libraries to process collections as well.

Читайте также:  Перенос строк css grid

@SotiriosDelimanolis, for all intents and purposes, yes it is specific to List, but if there are other interesting ways to work with, say, a Collection, I’d be interested to know them.

@DaveNewton, thanks for the idea. I’ve never used anything like that. Please take a look at my edited question and let me know if I understood what you meant.

13 Answers 13

The three forms of looping are nearly identical. The enhanced for loop:

is, according to the Java Language Specification, identical in effect to the explicit use of an iterator with a traditional for loop. In the third case, you can only modify the list contents by removing the current element and, then, only if you do it through the remove method of the iterator itself. With index-based iteration, you are free to modify the list in any way. However, adding or removing elements that come before the current index risks having your loop skipping elements or processing the same element multiple times; you need to adjust the loop index properly when you make such changes.

In all cases, element is a reference to the actual list element. None of the iteration methods makes a copy of anything in the list. Changes to the internal state of element will always be seen in the internal state of the corresponding element on the list.

Essentially, there are only two ways to iterate over a list: by using an index or by using an iterator. The enhanced for loop is just a syntactic shortcut introduced in Java 5 to avoid the tedium of explicitly defining an iterator. For both styles, you can come up with essentially trivial variations using for , while or do while blocks, but they all boil down to the same thing (or, rather, two things).

EDIT: As @iX3 points out in a comment, you can use a ListIterator to set the current element of a list as you are iterating. You would need to use List#listIterator() instead of List#iterator() to initialize the loop variable (which, obviously, would have to be declared a ListIterator rather than an Iterator ).

Источник

Java ArrayList forEach()

The ArrayList forEach() method performs the specified Consumer action on each element of the List until all elements have been processed or the action throws an exception.

By default, actions are performed on elements taken in the order of iteration.

1. Internal Implementation of forEach()

As shown below, the method iterates over all list elements and calls action.accept() for each element. Here the action is an instance of Consumer interface.

@Override public void forEach(Consumer action) < Objects.requireNonNull(action); final int expectedModCount = modCount; @SuppressWarnings("unchecked") final E[] elementData = (E[]) this.elementData; final int size = this.size; for (int i=0; modCount == expectedModCount && i < size; i++) < action.accept(elementData[i]); >if (modCount != expectedModCount) < throw new ConcurrentModificationException(); >>
  • Method parameter – The Consumer action to be performed for each element.
  • Method returns – void.
  • Method throwsConcurrentModificationException and NullPointerException.

2. ArrayList forEach() Examples

2.1. Print All List Items to the Console

Let us begin with a very simple Java program that just prints each of the elements from the List. We can apply the same code for ArrayList class as well.

List list = Arrays.asList("A","B","C","D"); list.forEach(System.out::println);

2.2. Custom Consumer Actions

A Consumer implementation takes a single argument, and returns no value. We can also pass the custom actions we have created in other places.

For example, the following code iterates a list and prints the lowercase strings using the forEach() API.

Consumer action = x -> System.out.println(x.toLowerCase()); list.forEach(action);

We can pass the simple lambda expression inline, as well.

list.forEach(e -> System.out.println(e.toLowerCase()));

If there are more than one statement in the Consumer action then use the curly braces to wrap the statements.

Источник

Как работает цикл foreach в Java?

Как выглядит цикл for , эквивалентный циклу foreach выше? Как работает цикл foreach внутри? В чем отличия циклов for и foreach ?

1 ответ 1

Цикл foreach — это синтаксический сахар. Внешне прежде всего отличается от for отсутствием явного счетчика. Единственное практическое различие между ними заключается в том, что в случае индексируемых объектов у вас нет доступа к индексу.

Цикл foreach позволяет выполнять итерации по двум типам объектов:

Цикл for , работающий с объектами Iterable

for(String item : someList) System.out.println(item); 
for (Iterator i = someIterable.iterator(); i.hasNext();)

Этот код работает для любого объекта, реализующего интерфейс Iterable .

В цикле foreach нельзя использовать метод remove(index) . Вместо этого следует использовать iterator.remove() . Пример:

for (Iterator iterator = list.iterator(); iterator.hasNext(); ) if (iterator.next() > 10) iterator.remove(); 

Если писать for без использования итератора, то вот примерная реализация foreach :

Циклы foreach и for , работающие с массивами

String[] fruits = new String[] < "Orange", "Apple", "Pear", "Strawberry" >; for (String fruit : fruits) < // fruit is an element of the `fruits` array. >

foreach против for — производительность

При доступе к коллекции, foreach значительно быстрее, чем for . Однако при доступе к массивам — по крайней мере с массивами примитивов и оболочек — доступ через индексы(т.е. используя for ) быстрее.

Также при вложенных циклах foreach наблюдаются проблемы с производительностью из-за создания большого количество объектов Iterator .

В Java 8 представили потоки, которые в целом работают лучше. (хоть эта информация напрямую и не относится к вопросу, но это может быть полезно)

someList.stream().forEach(System.out::println); 
Arrays.stream(someArray).forEach(System.out::println); 

UPD: Измерение производительности на JDK9

(не стоит серьезно его оценивать, т.к. мне не кажется, что я все правильно измерил)

Для замера производительности я использовал код из этого вопроса:

 public static void main(String[] args) < System.out.println(getTime()); >private static void testMethod() < //Код, время выполнения которого нужно узнать >/** * Метод для измерения времени выполнения метода testMethod * https://stackoverflow.com/a/2404378/7150209 */ private static double getTime() < for (int i = 0; i < 20; i ++) < //прогрев JVM testMethod(); >int count = 1000; //первоначальное кол-во повтора выполнения testMethod while(true) < long begin = System.nanoTime(); for (int i = 0; i < count; i ++) testMethod(); long end = System.nanoTime(); if ((end - begin) < 1000000000) < //Прогон тестов пока суммарное выполнения count раз count *= 100000; //testMethod`a не будет равно несколько секунд continue; >return (double)(end - begin) / count; > > 

Как работает метод getTime() — в цикле for метод с тестируемым кодом запускается count раз. Перед началом запусков засекается время, после всех запусков из конечного времени вычитается начальное — получается время запуска count раз тестового метода. После этого время делится на count — получается усредненное время одного запуска тестового метода. Если время запуска count раз тестового метода < 10 секунд, то count увеличивается, и замер происходит заново.

В тестовом методе в циклах for и foreach я использовал: переменная = list.get(i) / array[i] для for и переменная = i; для foreach .

В лямбде я использовал Arrays.stream(array).map(l -> l+1).collect(Collectors.toList()); и list.stream().map(l -> l+1).collect(Collectors.toList()) , т.е. изменение элементов коллекции и создание новой коллекции, поэтому выполнение лямбд заняло больше времени.

введите сюда описание изображения

В таблице видно, что выполнение в лямбде заняло примерно одинаковое время для коллекций и массивов. Время выполнения кода с массивом примерно в 1.5 раза быстрее, чем с коллекцией. Время выполнения цикла for и foreach для всех одинаковое.

P.S. Пример код for и foreach для коллекции(n — просто переменная):

Источник

Оцените статью