Автор оригинала: Vladimir Batoćanin.
Вступление
Метод forEach()
является частью интерфейса Stream
и используется для выполнения указанной операции, определенной Потребителем
.
Интерфейс Потребитель
представляет любую операцию, которая принимает аргумент в качестве входных данных и не имеет выходных данных. Такое поведение приемлемо, поскольку метод forEach()
используется для изменения состояния программы с помощью побочных эффектов, а не явных типов возвращаемых данных.
Поэтому наилучшими целевыми кандидатами для Потребителей
являются лямбда-функции и ссылки на методы. Стоит отметить, что forEach()
может использоваться в любой коллекции
.
forEach() в списке
Метод forEach()
является терминальной операцией, что означает, что после вызова этого метода поток вместе со всеми его интегрированными преобразованиями будет материализован. То есть они “обретут сущность”, а не будут транслироваться.
Давайте сгенерируем небольшой список:
Listlist = new ArrayList (); list.add(1); list.add(2); list.add(3);
Традиционно вы могли бы написать для каждого цикла, чтобы пройти через него:
for (Integer element : list) { System.out.print(element + " "); }
Это будет печатать:
1 2 3
В качестве альтернативы мы можем использовать метод forEach()
для потока
:
list.stream().forEach((k) -> { System.out.print(k + " "); });
Это также выводит:
1 2 3
Мы можем сделать это еще проще с помощью ссылки на метод:
list.stream().forEach(System.out::println);
forEach() на карте
Метод forEach()
действительно полезен, если мы хотим избежать цепочки многих потоковых методов. Давайте сгенерируем карту с несколькими фильмами и соответствующими оценками IMDB:
Mapmap = new HashMap (); map.put("Forrest Gump", 8.8); map.put("The Matrix", 8.7); map.put("The Hunt", 8.3); map.put("Monty Python's Life of Brian", 8.1); map.put("Who's Singin' Over There?", 8.9);
Теперь давайте распечатаем значения каждого фильма, у которого оценка выше, чем 8.4
:
map.entrySet() .stream() .filter(entry -> entry.getValue() > 8.4) .forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));
Это приводит к:
Forrest Gump: 8.8 The Matrix: 8.7 Who's Singin' Over There?: 8.9
Здесь мы преобразовали Карту
в Набор
через entrySet ()
, передали ее в потоковом режиме , отфильтровали на основе результатов и, наконец, распечатали их с помощью forEach()
. Вместо того , чтобы основывать это на возврате filter ()
, мы могли бы основать нашу логику на побочных эффектах и пропустить метод filter()
:
map.entrySet() .stream() .forEach(entry -> { if (entry.getValue() > 8.4) { System.out.println(entry.getKey() + ": " + entry.getValue()); } } );
Это приводит к:
Forrest Gump: 8.8 The Matrix: 8.7 Who's Singin' Over There?: 8.9
Наконец, мы можем опустить оба метода stream()
и filter ()
, начав с для каждого()
в начале:
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
map.forEach((k, v) -> { if (v > 8.4) { System.out.println(k + ": " + v); } });
Это приводит к:
Forrest Gump: 8.8 The Matrix: 8.7 Who's Singin' Over There?: 8.9
для Каждого() наступления
Давайте посмотрим, как мы можем использовать метод forEach
для Набора
в немного более осязаемом контексте. Во-первых, давайте определим класс, который представляет Сотрудника
компании:
public class Employee { private String name; private double workedHours; private double dedicationScore; // Constructor, Getters and Setters public void calculateDedication() { dedicationScore = workedHours*1.5; } public void receiveReward() { System.out.println(String .format("%s just got a reward for being a dedicated worker!", name)); } }
Представив себя менеджером, мы захотим выбрать определенных сотрудников, которые работали сверхурочно, и наградить их за тяжелую работу. Во-первых, давайте сделаем Набор
:
Setemployees = new HashSet (); employees.add(new Employee("Vladimir", 60)); employees.add(new Employee("John", 25)); employees.add(new Employee("David", 40)); employees.add(new Employee("Darinka", 60));
Затем давайте рассчитаем показатель преданности каждого сотрудника:
employees.stream().forEach(Employee::calculateDedication);
Теперь, когда у каждого сотрудника есть оценка самоотдачи, давайте удалим тех, у кого слишком низкий балл:
Setregular = employees.stream() .filter(employee -> employee.getDedicationScore() <= 60) .collect(Collectors.toSet()); employees.removeAll(regular);
Наконец, давайте вознаградим сотрудников за их усердную работу:
employees.stream().forEach(employee -> employee.receiveReward());
И для ясности давайте распечатаем имена счастливчиков:
System.out.println("Awarded employees:"); employees.stream().map(employee -> employee.getName()).forEach(employee -> System.out.println(employee));
После выполнения приведенного выше кода мы получим следующий вывод:
Vladimir just got a reward for being a dedicated worker! Darinka just got a reward for being a dedicated worker! Awarded employees: Vladimir Darinka
Побочные эффекты И Возвращаемые Значения
Смысл каждой команды состоит в том, чтобы оценить выражение от начала до конца. Все промежуточное-это побочный эффект . В этом контексте это означает изменение состояния, потока или переменных без возврата каких-либо значений.
Давайте взглянем на разницу в другом списке:
ListtargetList = Arrays.asList(1, -2, 3, -4, 5, 6, -7);
Этот подход основан на возвращаемых значениях из ArrayList
:
long result1 = targetList .stream() .filter(integer -> integer > 0) .count(); System.out.println("Result: " + result1);
Это приводит к:
Result: 4
И теперь, вместо того, чтобы основывать логику программы на типе возвращаемого значения, мы выполним forEach()
в потоке и добавим результаты в AtomicInteger
(потоки работают одновременно):
AtomicInteger result2 = new AtomicInteger(); targetList.stream().forEach(integer -> { if (integer > 0) result2.addAndGet(1); }); System.out.println("Result: " + result2);
Вывод
Метод forEach ()
– действительно полезный метод, который можно использовать для перебора коллекций в Java в функциональном подходе.
В некоторых случаях они могут значительно упростить код и повысить ясность и краткость. В этой статье мы рассмотрели основы использования forEach ()
, а затем рассмотрели примеры метода в Списке
, Карте
и Наборе
.
Мы рассмотрели разницу между циклом для каждого
и forEach()
, а также разницу между логикой, основанной на возвращаемых значениях, и побочными эффектами.