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

Какие знаешь два типа методов у Stream?

1.0 Junior🔥 191 комментариев
#Stream API и функциональное программирование

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

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

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

Два типа методов Stream API в Java

Stream API в Java содержит два принципиально различных типа методов, которые различаются по своему назначению и возвращаемому значению.

1. Промежуточные операции (Intermediate Operations)

Это методы, которые возвращают новый Stream и позволяют выполнять цепочку операций. Они ленивы (lazy) — выполняются только при вызове терминальной операции.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// Промежуточные операции не выполняются в этой строке!
Stream<Integer> stream = numbers.stream()
    .filter(n -> n > 2)        // Intermediate
    .map(n -> n * 2)           // Intermediate
    .distinct();               // Intermediate

// Выполнятся только при вызове терминальной операции
List<Integer> result = stream.collect(Collectors.toList());

Основные промежуточные операции:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// filter — оставляет только элементы, соответствующие предикату
Stream<Integer> filtered = numbers.stream()
    .filter(n -> n % 2 == 0);  // Результат: [2, 4, 6]

// map — преобразует каждый элемент
Stream<Integer> mapped = numbers.stream()
    .map(n -> n * 10);  // Результат: [10, 20, 30, 40, 50, 60]

// flatMap — преобразует в Stream и объединяет
Stream<Integer> flattened = numbers.stream()
    .flatMap(n -> Stream.of(n, n * 2));  // Развёртывает вложенные потоки

// distinct — удаляет дубликаты
Stream<Integer> unique = numbers.stream()
    .distinct();

// sorted — сортирует элементы
Stream<Integer> sorted = numbers.stream()
    .sorted();  // Можно передать компаратор: .sorted(Comparator.reverseOrder())

// limit — ограничивает количество элементов
Stream<Integer> limited = numbers.stream()
    .limit(3);  // Результат: [1, 2, 3]

// skip — пропускает первые N элементов
Stream<Integer> skipped = numbers.stream()
    .skip(2);  // Результат: [3, 4, 5, 6]

// peek — побочная операция для отладки
Stream<Integer> peeked = numbers.stream()
    .peek(n -> System.out.println("Processing: " + n))
    .filter(n -> n > 2);

2. Терминальные операции (Terminal Operations)

Это методы, которые завершают цепочку операций и возвращают конкретный результат (не Stream). После вызова терминальной операции Stream закрывается и больше не может быть использован.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// forEach — выполняет действие для каждого элемента (void)
integers.stream()
    .forEach(n -> System.out.println(n));

// collect — собирает элементы в коллекцию
List<Integer> collected = numbers.stream()
    .collect(Collectors.toList());

// count — подсчитывает количество элементов
long count = numbers.stream()
    .count();  // Результат: 6

// findFirst — возвращает первый элемент
Optional<Integer> first = numbers.stream()
    .findFirst();  // Результат: Optional[1]

// findAny — возвращает любой элемент
Optional<Integer> any = numbers.stream()
    .findAny();

// reduce — объединяет элементы в один
Optional<Integer> sum = numbers.stream()
    .reduce((a, b) -> a + b);  // Результат: Optional[21]

// min/max — находит минимум/максимум
Optional<Integer> min = numbers.stream()
    .min(Comparator.naturalOrder());
Optional<Integer> max = numbers.stream()
    .max(Comparator.naturalOrder());

// anyMatch/allMatch/noneMatch — проверяет условие
boolean hasEven = numbers.stream()
    .anyMatch(n -> n % 2 == 0);  // true
boolean allPositive = numbers.stream()
    .allMatch(n -> n > 0);  // true
boolean noNegative = numbers.stream()
    .noneMatch(n -> n < 0);  // true

Практический пример

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Alice");

List<String> result = names.stream()
    // Промежуточные операции (ленивы)
    .filter(name -> name.length() > 3)  // [Alice, Charlie, David, Alice]
    .map(String::toUpperCase)            // [ALICE, CHARLIE, DAVID, ALICE]
    .distinct()                          // [ALICE, CHARLIE, DAVID]
    .sorted()                            // [ALICE, CHARLIE, DAVID]
    // Терминальная операция (выполняет всю цепочку)
    .collect(Collectors.toList());       // Результат: [ALICE, CHARLIE, DAVID]

Ключевое отличие: промежуточные операции создают новые Stream и позволяют чейнить методы, а терминальные операции завершают обработку и возвращают конкретный результат.