Используются для обработки потока данных с помощью цепочки методов.
Поток (Stream): Поток представляет последовательность элементов данных. Он не хранит данные, а лишь обрабатывает их на лету при выполнении операций.
- благодаря стримам больше не нужно писать стереотипный код каждый раз, когда приходится что-то делать с данными: сортировать, фильтровать, преобразовывать. Разработчики меньше думают о стандартной реализации и больше времени уделяют более сложным вещам;
- методы Stream API не изменяют исходные коллекции, уменьшая количество побочных эффектов.
- Распараллеливать проведений операций с коллекциями стало проще. Там, где раньше пришлось бы проходить циклом, стримы значительно сокращают количество кода.
Выделяют два основных типов методов:
- конвейерные: операции применяются к потоку и возвращают новый поток. Они выполняются лениво, что означает, что они не изменяют исходный поток данных, а создают новый поток с примененными операциями.
- терминальные: применяются к потоку и возвращают результат. Они являются триггером для выполнения всех промежуточных операций и завершения обработки данных в потоке.
Фильтрует элементы потока согласно условию, заданному предикатом.
Пример: Список пользователей, имя которых содержит "М"
userList.stream().filter(user -> user.getFirstName().contains("M")).collect(Collectors.toSet()).forEach(System.out::println);Применяет функцию к каждому элементу потока и возвращает новый поток с преобразованными значениями.
Пример: создание списка из id-пользователей
List<Integer> ids = userList.stream().map(User::getId).map(Long::intValue).collect(Collectors.toList());
ids.forEach(System.out::println);Пример: получение нового списка пользователей с измененными полями
userList.stream().map(user -> new User(user.getId(), "X", "Y", 0, "XY")).forEach(System.out::println);Пример: замены имени пользователя
userList.stream().map(user -> {
if (user.getFirstName().equals("Michael")) {
return new User(user.getId(), "Nikita", user.getLastName(), user.getAge(), user.getNationality());
}
return user;
}).forEach(System.out::println);Применение flatMap позволяет объединить несколько потоков в один и получить плоский список элементов. Таким образом, flatMap часто применяется, когда у нас есть вложенные коллекции или списки, и мы хотим получить один плоский список всех элементов.
Пример: есть список из объектов Person, и каждый Person имеет список его друзей. Необходимо получить список всех друзей из всех Person.
public class Person {
private String name;
private List<Person> friends;
// Конструктор и геттеры
public static void main(String[] args) {
List<Person> persons = List.of(
new Person("Alice", List.of(new Person("Bob"), new Person("Charlie"))),
new Person("David", List.of(new Person("Eve"), new Person("Frank")))
);
List<Person> allFriends = persons.stream()
.flatMap(person -> person.getFriends().stream())
.toList();
allFriends.forEach(friend -> System.out.println(friend.getName()));
}
}Сортирует элементы потока в соответствии с компаратором
Пример: сортировка по возрастанию
userList.stream().sorted(Comparator.comparingInt(User::getAge))Пример: сортировка по убыванию
userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed())Пример: множественная сортировка
userList.stream().sorted(Comparator.comparing(User::getLastName).thenComparing(User::getFirstName))Предоставляет удобный способ получения статистической информации о числовом потоке, такой как количество элементов, сумму, минимальное и максимальное значение, среднее значение и т.д.
Пример:
List<Integer> ages = userList.stream().map(User::getAge).toList();
int minimalAge = ages.stream().min(Integer::compare).orElse(Integer.MAX_VALUE);
int maximalAge = ages.stream().max(Integer::compare).orElse(Integer.MIN_VALUE);
double averageAge = ages.stream().mapToInt(Integer::intValue).average().orElse(0);
int sum = ages.stream().mapToInt(Integer::intValue).sum();
long count = ages.stream().count();Проверяют соответстиве элементов соответственно предикату.
Пример: проверка на то, что возраст всех пользователей больше 76
boolean isAllAgesGreaterThan76 = userList.stream().allMatch(user -> user.getAge() > 76);Пример: проверка на то, что возраст хотя бы одного пользователя больше 76
boolean isAnyAgesGreaterThan76 = userList.stream().anyMatch(user -> user.getAge() > 76);int maxFirstnameLength = userList.stream().mapToInt(user -> user.getFirstName().length()).summaryStatistics().getMax();Set<User> userSet = userList.stream().collect(Collectors.toSet());
LinkedList<User> userLinkedList = userList.stream().collect(Collectors.toCollection(LinkedList::new));
Map<Long, User> userMap = userList.stream().collect(Collectors.toMap(user -> user.getId(), user -> user));