← Назад к вопросам

Приведи примеры методов к каждому виду методов Stream

1.6 Junior🔥 91 комментариев
#ООП#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Методы Stream API в Java

Отличный вопрос про Stream API! Это один из самых мощных инструментов Java для работы с коллекциями. Давайте разберём все виды методов.

Три категории методов Stream

Существует три типа методов:

  1. Intermediate operations (промежуточные) - возвращают Stream
  2. Terminal operations (терминальные) - возвращают результат
  3. 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: комбинируй методы для читаемого и выразительного кода!