Java for arraylist foreach

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

Читайте также:  Php exec with parameters

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.

Источник

Лямбды и ссылки на методы в ArrayList.forEach — как это работает

Java-университет

Знакомство с лямбда-выражениями в квесте Java Syntax Zero начинается с крайне специфического примера:

 ArrayList list = new ArrayList<>(); Collections.addAll(list, "Привет", "как", "дела?"); list.forEach( (s) -> System.out.println(s) ); 

Авторы лекции разбирают лямбды и ссылки на методы с помощью стандартной функции forEach класса ArrayList. Лично мне было трудно понять смысл происходящего, поскольку реализация этой функции, равно как и связанного с ней интерфейса, остается «под капотом». Откуда берётся аргумент (s), куда передаётся функция println() — вопросы, на которые нам придётся отвечать самостоятельно. К счастью, с помощью IntelliJ IDEA мы легко можем заглянуть во внутреннее устройство класса ArrayList и размотать эту лапшу от самого начала. Если вы тоже ничего не поняли и хотите разобраться, постараюсь вам в этом хоть немного помочь. Лямбда-выражение и ArrayList.forEach — как это работает Из лекции мы уже знаем, что лямбда-выражение — это реализация функционального интерфейса. То есть мы объявляем интерфейс с одной-единственной функцией, а с помощью лямбды описываем, что эта функция делает. Для этого нужно: 1. Создать функциональный интерфейс; 2. Создать переменную, тип которой соответствует функциональному интерфейсу; 3. Присвоить этой переменной лямбда-выражение, которое описывает реализацию функции; 4. Вызвать функцию через обращение к переменной (возможно, я грубоват в терминологии, но так понятнее всего). Приведу простейший пример из гугла, снабдив его подробными комментариями (спасибо авторам сайта metanit.com):

 interface Operationable < int calculate(int x, int y); // Единственная функция в интерфейсе — значит, это функциональный интерфейс, // который можно реализовать с помощью лямбды >public class LambdaApp < public static void main(String[] args) < // Создаём переменную operation типа Operationable (так называется наш функциональный интерфейс) Operationable operation; // Прописываем реализацию функции calculate с помощью лямбды, на вход подаём x и y, на выходе возвращаем их сумму operation = (x,y)->x+y; // Теперь мы можем обратиться к функции calculate через переменную operation int result = operation.calculate(10, 20); System.out.println(result); //30 > > 

Теперь вернемся к примеру из лекции. В коллекцию list добавляются несколько элементов типа String. Затем элементы выводятся с помощью стандартной функции forEach, которая вызывается у объекта list. В качестве аргумента в функцию передается лямбда-выражение с каким-то странным параметром s.

 ArrayList list = new ArrayList<>(); Collections.addAll(list, "Привет", "как", "дела?"); list.forEach( (s) -> System.out.println(s) ); 

Если вы с ходу не поняли, что тут произошло, то вы не одиноки. К счастью, в IntelliJ IDEA есть замечательная комбинация клавиш Ctrl+Левая_Кнопка_Мыши. Если навести курсор на forEach и нажать эту комбинацию, откроется исходник стандартного класса ArrayList, в котором мы увидим реализацию метода forEach:

 public void forEach(Consumer action)

Мы видим, что на вход подаётся аргумент action типа Consumer. Наведем курсор на слово Consumer и снова нажмем волшебную комбинацию Ctrl+LMB. Откроется описание интерфейса Consumer. Если убрать из него default-реализацию (нам она сейчас не важна), увидим вот такой код:

public interface Consumer

Итак. У нас есть интерфейс Consumer с единственной функцией accept, которая принимает один аргумент любого типа. Раз функция одна, значит интерфейс функциональный, и его реализацию можно прописать через лямбда-выражение. Мы уже выяснили, что в ArrayList есть функция forEach, которая принимает на вход реализацию интерфейса Consumer в качестве аргумента action. Кроме того, в функции forEach мы находим вот такой код:

 for (int i = 0; modCount == expectedModCount && i < size; i++) action.accept(elementAt(es, i)); 

Цикл for по сути перебирает все элементы коллекции ArrayList. Внутри цикла мы видим вызов функции accept объекта action — помните, как мы обращались к operation.calculate? В функцию accept передаётся текущий элемент коллекции. Теперь мы наконец можем вернуться к исходному лямбда-выражению и понять, что же оно делает. Соберём весь код в одну кучу:

 public interface Consumer  < void accept(T t); // Функция, которую мы реализуем лямбда-выражением >public void forEach(Consumer action) // В action хранится объект Consumer, в котором функция accept реализована нашей лямбдой < Objects.requireNonNull(action); final int expectedModCount = modCount; final Object[] es = elementData; final int size = this.size; for (int i = 0; modCount == expectedModCount && i < size; i++) action.accept(elementAt(es, i)); // Вызываем нашу реализацию функции accept интерфейса Consumer для каждого элемента коллекции if (modCount != expectedModCount) throw new ConcurrentModificationException(); >//. list.forEach( (s) -> System.out.println(s) ); 

Наше лямбда-выражение — это реализация функции accept, описанной в интерфейсе Consumer. С помощью лямбды мы прописали, что функция accept принимает аргумент s и выводит его на экран. Лямбда-выражение было передано в функцию forEach в качестве ее аргумента action, который как раз и хранит в себе реализацию интерфейса Consumer. Теперь функция forEach может вызвать нашу реализацию интерфейса Consumer с помощью вот такой строки:

 action.accept(elementAt(es, i)); 

Таким образом, входной аргумент s в лямбда-выражении — это очередной элемент коллекции ArrayList, который передается в нашу реализацию интерфейса Consumer. На этом всё: логику работы лямбда-выражения в ArrayList.forEach мы разобрали. Ссылка на метод в ArrayList.forEach — а это как работает? Следующим шагом в лекции разбираются ссылки на методы. Правда, разбираются они как-то совсем странно — после прочтения лекции у меня не было никаких шансов понять, что же делает этот код:

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

Для начала вновь немного теории. Ссылка на метод — это, если очень грубо, реализация функционального интерфейса, описанная другой функцией. Опять же начну с простого примера:

 public interface Operationable < int calculate(int x, int y); // Единственная функция в интерфейсе — значит, это функциональный интерфейс >public static class Calculator < // Создадим статический класс Calculator и пропишем в нём метод methodReference. // Именно он будет реализовывать функцию calculate из интерфейса Operationable. public static int methodReference(int x, int y) < return x+y; >> public static void main(String[] args) < // Создаём переменную operation типа Operationable (так называется наш функциональный интерфейс) Operationable operation; // Теперь реализацией интерфейса будет не лямбда-выражение, а метод methodReference из нашего класса Calculator operation = Calculator::methodReference; // Теперь мы можем обратиться к функции интерфейса через переменную operation int result = operation.calculate(10, 20); System.out.println(result); //30 >
 list.forEach( System.out::println ); 

Напомню, что System.out — это объект типа PrintStream, у которого есть функция println. Давайте наведём курсор на println и щёлкнем Ctrl+LMB:

 public void println(String x) < if (getClass() == PrintStream.class) < writeln(String.valueOf(x)); >else < synchronized (this) < print(x); newLine(); >> > 

Отметим две ключевые особенности: 1. Функция println ничего не возвращает (void). 2. Функция println получает на вход один аргумент. Ничего не напоминает?

public interface Consumer

Всё правильно — сигнатура функции accept — это более общий случай сигнатуры метода println! Значит, последний можно с успехом использовать в качестве ссылки на метод — то есть println становится конкретной реализацией функции accept:

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

Мы передали функцию println объекта System.out в качестве аргумента функции forEach. Принцип тот же, что и с лямбдой: теперь forEach может передать элемент коллекции в функцию println через обращение action.accept(elementAt(es, i)). Фактически теперь это можно читать как System.out.println(elementAt(es, i)).

 public void forEach(Consumer action) // В action хранится объект Consumer, в котором функция accept реализована методом println < Objects.requireNonNull(action); final int expectedModCount = modCount; final Object[] es = elementData; final int size = this.size; for (int i = 0; modCount == expectedModCount && i < size; i++) action.accept(elementAt(es, i)); // Функция accept теперь реализована методом System.out.println! if (modCount != expectedModCount) throw new ConcurrentModificationException(); >

Надеюсь, что я хоть немного прояснил ситуацию для тех, кто впервые знакомится с лямбдами и ссылками на методы. В заключение порекомендую известнейшую книгу "Java: руководство для начинающих" под авторством Роберта Шилдта — на мой взгляд, лямбды и ссылки на функции в ней описаны довольно толково.

Источник

Java ArrayList forEach

Java Course - Mastering the Fundamentals

In Java, the ArrayList collection has a method called forEach() , which lets us perform some operation on each element of the collection. The method traverses each element of the Iterable of ArrayList until all elements have been processed or an exception is raised.

Syntax of ArrayList forEach() in Java

The syntax for forEach() method is:

ArrayList forEach in Java

Parameters of ArrayList forEach() in Java

forEach() method takes in a single parameter: action, which represents the action to be performed for each element.

Consumer is a class that can be used when an object needs to be taken as input, and some operation is to be performed on the object without returning any result.

E signifies the data type of the ArrayList on which the action is being performed.

Thus the only parameter action is the operation that needs to be performed on each item in the ArrayList of data type E .

Return Values of ArrayList forEach() in Java

forEach() method does not return any value.

Exceptions of ArrayList forEach() in Java

NullPointerException: forEach throws a NullPointerException if the action passed to the method is null.

Example

We mostly use lambda functions within forEach to perform a certain operation on the items in the ArrayList .

For example, consider the following operation where we are printing the elements of a list line by line.

What is ArrayList forEach() in Java?

We should use forEach instead of conventional for loops, especially when we wish to use lambda functions. This is because the lambda function avoids the creation of bulky classes.

Lambda functions are similar to methods, but they do not need a name, and they can be implemented right in the body of a method.

The above code using the lambda function can be written as:

The code becomes much cleaner and more elegant to look at.

Furthermore, the forEach operator uses an Internal Iterator which manages the iteration in the background and leaves the developer to just code what is supposed to be done with the elements of the collection. The iterator is responsible for iterating through the elements one by one.

In the example above, the argument provided is a lambda expression. This means that the method only needs to know what is to be done, and how iteration has to be done is taken care of internally.

More Examples

Example 1: ArrayList forEach() in Java

Let us say we have a list of strings that we wish to concatenate to make a line.

One by one, the strings in the words list would be concatenated, resulting in the following output:

Example 2: forEach() Method on ArrayList Which Contains a List of Numbers

Let us write a simple program to double the numbers in a list of Integers:

For every number in the list, we will multiply the number by 2 and update it in the same list itself.

forEach method containing list of Numbers

Example 3: forEach() Method on ArrayList Which Contains list of Objects

Let us now take a fairly elaborate example where you want to create a list of objects in a retail store from a given list of items.

For every item in the store list, we create an Item object and increment a counter to store the id. These item objects are appended to a separate list.

forEach method containing list of objects

Conclusion

  • forEach() is used to iterate over the element of an ArrayList.
  • forEach() expects an action as an argument and applies the action to each element.
  • If the action is null , then it results in a NullPointerException.
  • forEach() works excellent with lambda functions by avoiding the creation of bulky classes to define methods.

Источник

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