Java 8 запустила одну из своих лучших функций: лямбда-функции – первый шаг Java к функциональному программированию. В основном это означает, что функции могут создаваться без класса, а также могут передаваться с помощью методов.
Лямбда-функции очень помогают при работе с коллекциями. Вместо того, чтобы проходить циклы, чтобы манипулировать их значениями, лямбда-функции обеспечивают быстрый и гораздо более читаемый способ манипулирования ими. Рассмотрение всех деталей того, как они работают, заняло бы гораздо больше, чем один пост в блоге. Поэтому здесь будут показаны наиболее часто используемые функции, по крайней мере, по моему скромному опыту.
Безусловно, самая полезная задача, которую можно было бы выполнить с коллекцией, – это отфильтровать ее. И это может быть достигнуто с помощью следующего кода:
Listints = Arrays.asList(12, 32, 1, 3, 5, 3, 10, 8, 100); List filteredElements = ints.stream().filter(element -> element > 10) .collect(Collectors.toList());
Как можно заметить, код довольно прост: создается список целых чисел ints , затем вызывается метод stream() . Это обеспечивает возможность использования функционального программирования, уже встроенного. Здесь используется метод filter(...) , и он выполняет следующие действия:
- для каждого элемента в коллекции
intsприменяется логическая функция. В этом случае он проверяет, превышает ли каждый элемент 10:элемент > 10. Когда это верно, элемент передается обрабатываемому следующему функциональному методу.
Далее|/| .собирать (коллекционеры.Применяется функция ToList()) , которая преобразует результат фильтра(…) в список целых чисел, представленных переменной: filteredElements . Ниже приведен результат печати результирующей коллекции (вспомогательные методы используются для красивой печати результатов в статье, но они не перечислены, потому что они довольно просты):
Filter Integers higher than 10: [12, 32, 100]
Обратите внимание, насколько проще и понятнее использование метода filter(...) . Только с первого взгляда разработчик может понять назначение метода. Это гораздо легче читать, чем взаимодействие через набор целых чисел и добавление в новый список только тех элементов, которые превышают 10. Кроме того, он менее многословен.
Метод фильтрации также может быть применен к параметрам объекта, как показано ниже:
ListpeopleList = Person.createPersonList(); List filteredPersonList = peopleList.stream().filter(person -> person.getAge() > 30).collect(Collectors.toList());
Здесь он фильтруется из списка, только элементы объекта Человек , у которого параметр возраст превышает 30. Лицо объекта определено ниже (обратите внимание, что функция Также отображается createPersonList() ):
public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
+ age +
", name='" + name + '\'' +
'}';
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isPersonCool() {
return this.age > 40;
}
public static List createPersonList() {
List personList = new ArrayList<>();
personList.add(new Person(18, "Little person"));
personList.add(new Person(25, "Young adult"));
personList.add(new Person(33, "Responsible adult"));
personList.add(new Person(45, "Almost grandfather"));
personList.add(new Person(60, "Mein Opa"));
return personList;
}
}
Все еще говоря о фильтрации, можно применить любую логическую функцию для применения в качестве фильтра . Здесь функция является ли человек крутым (реализовано выше), будет применен:
ListpeopleList = Person.createPersonList(); List filteredPersonList = peopleList.stream().filter(Person::isPersonCool).collect(Collectors.toList());
Обратите внимание, как обозначение Случаи::функция может использоваться для упрощения обозначения, когда булева функция применяется как Человек::Человек классный . Это улучшает читабельность и делает код более чистым. Поскольку кто-то крутой – это человек старше 40 лет, результатом выполнения описанной выше функции является:
Filter by cool people: [Person{age=45, name='Almost grandfather'}, Person{age=60, name='Mein Opa'}]
Еще одна полезная задача для списков – сопоставление одного объекта с другим. Такая деятельность также может быть легко выполнена с помощью лямбда-функций. В следующем примере список объектов Человек будет сопоставлен с объектами Супергерой . Ниже приведена реализация класса Супергерой :
public class Superhero {
private int age;
private String name;
private String superPower;
public Superhero(int age, String name, String superPower) {
this.age = age;
this.name = name;
this.superPower = superPower;
}
@Override
public String toString() {
return "Superhero{" +
+ age +
", name='" + name + '\'' +
", superPower='" + superPower + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSuperPower() {
return superPower;
}
public void setSuperPower(String superPower) {
this.superPower = superPower;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
А вот карта(...) пример использования:
Listsuperheroes = personList .stream() .map(person -> new Superhero(person.getAge(), person.getName(), "fly")).collect( Collectors.toList());
В приведенном выше коде вот что происходит:
- для каждого экземпляра объекта
Personсоздается новый экземплярСупергерояс параметрамивозрастиимяот связанногоЧеловека, и с третьим параметромлетатькак сверхдержава. - Каждый экземпляр
Супергероязатем передается следующей лямбда-функции для обработки. - Затем функция
collect (Коллекторы.Применяется ToList()). Он собирает результат предыдущего преобразования (сопоставления) и помещает вСписокобъектовСупергероя.
Результат преобразования, изображен ниже:
Map ordinary people to superheroes: [Superhero{age=18, name='Little person', superPower='fly'}, Superhero{age=25, name='Young adult', superPower='fly'}, Superhero{age=33, name='Responsible adult', superPower='fly'}, Superhero{age=45, name='Almost grandfather', superPower='fly'}, Superhero{age=60, name='Mein Opa', superPower='fly'}]
До сих пор фильтрация и сопоставление данных применялись отдельно. Однако ничто не запрещает использовать их вместе, как показано в примере ниже:
ListcoolSuperheroes = Person.createPersonList().stream() .filter(Person::isPersonCool) .map(coolPeople -> new Superhero(coolPeople.getAge(), coolPeople.getName(), "be invisible")) .collect(Collectors.toList());
В приведенном выше примере список Людей фильтруется по критериям, кто крут, по использованию функции Человек::Человек Классный . После этого все крутые люди превращаются в супергероев , используя отображение: .карта(крутые люди ->новый супергерой(coolpeople.getAge(), coolPeople.getName(), "быть невидимым")) . Последним шагом является сбор списка Супергероев объектов с помощью .коллекционировать (Коллекционеры.тоЛист ()) . Результат обсуждаемого кода можно увидеть ниже:
Filter by coolness and map to superheroes: [Superhero{age=45, name='Almost grandfather', superPower='be invisible'}, Superhero{age=60, name='Mein Opa', superPower='be invisible'}]
Выполнение арифметических действий с данными коллекций – еще одно распространенное действие в коллекции. Конечно, это также поддерживается лямбда-функциями.
Ниже приведен пример, в котором суммируются все элементы целочисленного списка:
Listintegers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); int sumResult = integers.stream().mapToInt(Integer::intValue).sum();
В приведенном выше примере сначала список целых чисел вызывает метод stream() , чтобы получить доступ к лямбда-функциям. Затем каждый элемент сопоставляется целому числу. Таким образом, у вас есть доступ к функции sum() , которая, как следует из ее названия, суммирует все элементы в отображенной функции. Результат показан ниже:
Sum ints using IntStream.sum(): 45
Одной интересной функцией, которую можно использовать для суммирования всех элементов в списке, является уменьшить . Он выполняет следующие действия:
для списка
l, есть значение аккумулятораa. Каждый элемент списка называетсяe.- функция сокращения
rприменяется к каждому элементуe. Функцияrимеет в качестве своего первого параметра аккумуляторaи текущее значение спискаe. Функция уменьшения имеет в качестве возвращаемого значения новый накопительa, который является результатом того, какой алгоритм использовался для функции уменьшенияr.
- функция сокращения
Действительно, приведенное выше определение является довольно общим и трудным для понимания. Поэтому смотрите пример ниже, который сделает все намного более понятным:
Listintegers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); int sumResult = integers.stream().reduce(0, (a, e) -> a + e);``` {% endraw %} Note the reduce function {% raw %}`r`{% endraw %} sums the previous accumulator value {% raw %}`a`{% endraw %} with the current element {% raw %}`e`{% endraw %}. So, for each element of the list, its value is summed to the total already calculated before. The initial value for the accumulated value {% raw %}`a`{% endraw %} is zero, as defined here: {% raw %}`reduce(0, (a, e) -> a + e)`{% endraw %}. Other interesting functions are provided, such as calculating the average of a list of numbers: {% raw %} ```java List integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); OptionalDouble meanResult = integers.stream().mapToInt(Integer::intValue).average();
Вычисление максимального значения списка:
Listintegers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); OptionalInt maxResult = integers.stream().mapToInt(Integer::valueOf).max();
И, конечно же, расчет минимального:
Listintegers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); OptionalInt minResult = integers.stream().mapToInt(Integer::valueOf).min();
Как и ожидалось, все три обсуждаемых типа лямбда-функций могут быть объединены, как в примере ниже:
OptionalDouble averageAge = Person.createPersonList().stream()
.filter(Person::isPersonCool)
.map(coolPeople -> new Superhero(coolPeople.getAge(), coolPeople.getName(), "be invisible"))
.mapToInt(Superhero::getAge)
.average();
Здесь коллекция Человек объектов фильтруется по прохладе. Затем они сопоставляются со списком объектов Супергерой , чтобы затем вычислить среднее значение их возраста.
Пожалуйста, обратите внимание, что здесь обсуждались не все лямбда-функции, а только наиболее распространенные. Конечно, читатели могут не согласиться с тем, что является более распространенным или полезным. Несмотря на это, будет трудно найти разработчика, который не найдет их весьма полезными. Поэтому, если вы новичок в этой теме, это послужит быстрой и приятной отправной точкой.
Более того, обратите внимание, как легко понять значение каждого из них. Наличие имен, описывающих, что именно происходит, гораздо более читаемо, чем наличие циклов и если предложений внутри них для достижения той же цели.
Вы можете найти весь исходный код, используемый в этой статье здесь .
Оригинал: “https://dev.to/dufernandes/my-most-used-java-8-lambda-functions-269i”