Приведи примеры методов к каждому виду методов Stream
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы Stream API в Java
Отличный вопрос про Stream API! Это один из самых мощных инструментов Java для работы с коллекциями. Давайте разберём все виды методов.
Три категории методов Stream
Существует три типа методов:
- Intermediate operations (промежуточные) - возвращают Stream
- Terminal operations (терминальные) - возвращают результат
- Short-circuit operations (короткие замыкания) - могут завершиться раньше
1. Intermediate Operations (Промежуточные операции)
Промежуточные операции возвращают Stream и могут быть "ленивыми".
map() - преобразование элементов:
// Преобразуем String в Integer
List<String> numbers = Arrays.asList("1", "2", "3", "4", "5");
List<Integer> intNumbers = numbers.stream()
.map(Integer::parseInt)
.collect(Collectors.toList());
// [1, 2, 3, 4, 5]
// Преобразуем объекты
List<User> users = getUserList();
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
filter() - отфильтровать элементы:
// Оставляем только чётные числа
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evens = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// [2, 4, 6, 8, 10]
// Фильтруем объекты
List<User> adults = users.stream()
.filter(user -> user.getAge() >= 18)
.collect(Collectors.toList());
flatMap() - преобразование и "разворачивание":
// Преобразуем список списков в один список
List<List<Integer>> listOfLists = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5),
Arrays.asList(6, 7, 8)
);
List<Integer> flat = listOfLists.stream()
.flatMap(List::stream) // разворачиваем каждый список
.collect(Collectors.toList());
// [1, 2, 3, 4, 5, 6, 7, 8]
// Преобразуем объекты с коллекциями
List<Order> orders = getOrders();
List<Item> allItems = orders.stream()
.flatMap(order -> order.getItems().stream())
.collect(Collectors.toList());
distinct() - удалить дубликаты:
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 5, 5);
List<Integer> unique = numbers.stream()
.distinct()
.collect(Collectors.toList());
// [1, 2, 3, 4, 5]
sorted() - сортировка:
// Сортировка по умолчанию
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);
List<Integer> sorted = numbers.stream()
.sorted()
.collect(Collectors.toList());
// [1, 2, 5, 8, 9]
// Сортировка с компаратором
List<User> users = getUserList();
List<User> sortedByAge = users.stream()
.sorted(Comparator.comparing(User::getAge))
.collect(Collectors.toList());
// Сортировка в обратном порядке
List<User> sortedDescending = users.stream()
.sorted(Comparator.comparing(User::getAge).reversed())
.collect(Collectors.toList());
peek() - просмотр элементов для отладки:
// peek используется для отладки, не изменяет данные
List<Integer> result = numbers.stream()
.filter(n -> n > 2)
.peek(n -> System.out.println("Filtered: " + n))
.map(n -> n * 2)
.peek(n -> System.out.println("Mapped: " + n))
.collect(Collectors.toList());
// Output:
// Filtered: 3
// Mapped: 6
// Filtered: 4
// Mapped: 8
limit() и skip() - контроль количества:
// Первые 3 элемента
List<Integer> first3 = numbers.stream()
.limit(3)
.collect(Collectors.toList());
// [1, 2, 3]
// Пропустить первые 2, взять следующие 3
List<Integer> range = numbers.stream()
.skip(2)
.limit(3)
.collect(Collectors.toList());
// [3, 4, 5]
// Пример с пагинацией
List<User> page = users.stream()
.skip((pageNumber - 1) * pageSize)
.limit(pageSize)
.collect(Collectors.toList());
2. Terminal Operations (Терминальные операции)
Терминальные операции завершают Stream и возвращают результат.
collect() - собрать результаты:
// Собрать в List
List<String> list = names.stream().collect(Collectors.toList());
// Собрать в Set
Set<String> set = names.stream().collect(Collectors.toSet());
// Собрать в Map
Map<Integer, User> userMap = users.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
// Собрать в строку
String csv = names.stream().collect(Collectors.joining(", "));
// "John, Jane, Bob"
// Группировка по возрасту
Map<Integer, List<User>> byAge = users.stream()
.collect(Collectors.groupingBy(User::getAge));
// Подсчёт элементов по категории
Map<String, Long> countByCity = users.stream()
.collect(Collectors.groupingBy(User::getCity, Collectors.counting()));
forEach() - выполнить для каждого:
numbers.stream()
.forEach(n -> System.out.println(n));
users.stream()
.forEach(user -> saveToDatabase(user));
reduce() - свёртка в один результат:
// Сумма всех чисел
int sum = numbers.stream()
.reduce(0, Integer::sum);
// 55
// Произведение
int product = numbers.stream()
.reduce(1, (a, b) -> a * b);
// 3628800
// С Optional (если нет начального значения)
Optional<Integer> max = numbers.stream()
.reduce(Integer::max);
// Optional[10]
// Конкатенация строк
String result = names.stream()
.reduce("", (acc, name) -> acc + ", " + name)
.substring(2);
count() - подсчёт элементов:
long count = numbers.stream().count(); // 10
long adults = users.stream()
.filter(user -> user.getAge() >= 18)
.count();
min() и max() - поиск экстремумов:
Optional<Integer> minimum = numbers.stream()
.min(Comparator.naturalOrder());
Optional<Integer> maximum = numbers.stream()
.max(Comparator.naturalOrder());
Optional<User> oldestUser = users.stream()
.max(Comparator.comparing(User::getAge));
toArray() - преобразование в массив:
Integer[] array = numbers.stream().toArray(Integer[]::new);
String[] namesArray = names.stream().toArray(String[]::new);
3. Short-Circuit Operations (Операции короткого замыкания)
Эти операции могут завершиться раньше, не обрабатывая все элементы.
anyMatch() - есть ли хоть один:
boolean hasEven = numbers.stream()
.anyMatch(n -> n % 2 == 0);
// true - нашли одно чётное число и остановились
boolean hasAdult = users.stream()
.anyMatch(user -> user.getAge() >= 18);
allMatch() - все ли:
boolean allPositive = numbers.stream()
.allMatch(n -> n > 0);
// true - только если ВСЕ положительные
boolean allAdults = users.stream()
.allMatch(user -> user.getAge() >= 18);
noneMatch() - ни один не:
boolean noNegative = numbers.stream()
.noneMatch(n -> n < 0);
// true - нет отрицательных
boolean noMinors = users.stream()
.noneMatch(user -> user.getAge() < 18);
findFirst() - первый элемент:
Optional<Integer> first = numbers.stream()
.filter(n -> n > 5)
.findFirst();
// Optional[6]
findAny() - любой элемент:
Optional<Integer> any = numbers.stream()
.filter(n -> n > 5)
.findAny();
// Optional[6] (в параллельных потоках может быть другой)
Практический пример - комбинация
public List<String> getTopCitiesOfAdultUsers(List<User> users) {
return users.stream()
// 1. Intermediate: filter
.filter(user -> user.getAge() >= 18) // только взрослые
// 2. Intermediate: map
.map(User::getCity) // получаем города
// 3. Intermediate: distinct
.distinct() // уникальные города
// 4. Intermediate: sorted
.sorted() // сортируем
// 5. Intermediate: limit
.limit(10) // берём топ 10
// 6. Terminal: collect
.collect(Collectors.toList());
}
Таблица методов Stream
| Метод | Тип | Описание | Возвращает |
|---|---|---|---|
map() | Intermediate | Преобразовать элементы | Stream |
filter() | Intermediate | Отфильтровать | Stream |
flatMap() | Intermediate | Преобразовать и развернуть | Stream |
distinct() | Intermediate | Удалить дубликаты | Stream |
sorted() | Intermediate | Отсортировать | Stream |
limit() | Intermediate | Ограничить количество | Stream |
skip() | Intermediate | Пропустить N элементов | Stream |
peek() | Intermediate | Просмотр для отладки | Stream |
collect() | Terminal | Собрать в коллекцию | Collection |
forEach() | Terminal | Выполнить для каждого | void |
reduce() | Terminal | Свернуть в один результат | Optional/Value |
count() | Terminal | Подсчитать | long |
min()/max() | Terminal | Минимум/максимум | Optional |
anyMatch() | Short-circuit | Есть ли один | boolean |
allMatch() | Short-circuit | Все ли | boolean |
noneMatch() | Short-circuit | Ни один не | boolean |
findFirst() | Short-circuit | Первый | Optional |
findAny() | Short-circuit | Любой | Optional |
Важные моменты
1. Ленивость промежуточных операций:
List<Integer> result = numbers.stream()
.peek(n -> System.out.println("Filter: " + n))
.filter(n -> n > 2)
.peek(n -> System.out.println("Passed: " + n))
.collect(Collectors.toList()); // Сначала выполняется при collect()!
2. Stream одноразовый:
Stream<Integer> stream = numbers.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println); // ERROR: Stream has already been operated
Вывод
Stream API предоставляет мощный функциональный подход к работе с данными:
- Intermediate методы - преобразование и фильтрация
- Terminal методы - получение результата
- Short-circuit методы - оптимизация с ранним завершением
Best Practice: комбинируй методы для читаемого и выразительного кода!