Автор оригинала: 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() , а также разницу между логикой, основанной на возвращаемых значениях, и побочными эффектами.