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

Что такое конвейерный метод в Stream?

2.0 Middle🔥 161 комментариев
#Stream API и функциональное программирование

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

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

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

Конвейерный метод в Stream API

Конвейерный метод это метод в Stream API, который возвращает новый Stream, позволяя вызывать следующий метод в цепи. Это основа функционального программирования в Java.

Определение

Конвейерный метод (Intermediate operation):

  • Возвращает Stream (не завершает обработку)
  • Позволяет продолжить цепь вызовов
  • Работает лениво (вычисления отложены)
  • Позволяет написать gluent interface код
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Каждый метод возвращает Stream
numbers.stream()         // Stream<Integer>
    .filter(x -> x > 2)  // Stream<Integer> (конвейерный)
    .map(x -> x * 2)     // Stream<Integer> (конвейерный)
    .forEach(System.out::println);  // void (терминальный)

Список конвейерных методов

1. filter() — отфильтровать элементы

Stream<Integer> stream = numbers.stream()
    .filter(x -> x > 2);  // Возвращает Stream

2. map() — преобразовать элементы

Stream<String> stream = numbers.stream()
    .map(x -> "number: " + x);  // Возвращает Stream

3. flatMap() — развернуть вложенные потоки

Stream<Integer> stream = numbers.stream()
    .flatMap(n -> Stream.of(n, n * 2));  // Возвращает Stream

4. distinct() — удалить дубликаты

Stream<Integer> stream = numbers.stream()
    .distinct();  // Возвращает Stream

5. sorted() — отсортировать

Stream<Integer> stream = numbers.stream()
    .sorted();  // Возвращает Stream

6. limit() — ограничить количество

Stream<Integer> stream = numbers.stream()
    .limit(3);  // Возвращает Stream с максимум 3 элементами

7. skip() — пропустить количество

Stream<Integer> stream = numbers.stream()
    .skip(2);  // Пропустить первые 2 элемента

8. peek() — выполнить действие без изменений

Stream<Integer> stream = numbers.stream()
    .peek(x -> System.out.println("Processing: " + x));

Пример конвейерной цепи

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

List<Integer> result = numbers.stream()
    .filter(x -> x > 2)        // Конвейерный: 3, 4, 5, 6
    .map(x -> x * 2)           // Конвейерный: 6, 8, 10, 12
    .limit(2)                  // Конвейерный: 6, 8
    .collect(Collectors.toList());  // Терминальный

System.out.println(result);  // [6, 8]

Ленивые вычисления (Lazy Evaluation)

Конвейерные методы работают лениво. Вычисления происходят только когда вызвали терминальный метод.

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

// На этом этапе НИЧЕГО не вычисляется
Stream<Integer> stream = numbers.stream()
    .filter(x -> {
        System.out.println("Filtering " + x);
        return x > 2;
    })
    .map(x -> {
        System.out.println("Mapping " + x);
        return x * 2;
    });

System.out.println("Stream created (nothing computed yet)");

// СЕЙЧАС произойдут вычисления (терминальный метод)
stream.forEach(System.out::println);

Вывод:

Stream created (nothing computed yet)
Filtering 1
Filtering 2
Filtering 3
Mapping 3
6
Filtering 4
Mapping 4
8
Filtering 5
Mapping 5
10

Конвейерный vs Терминальный

// Конвейерный — возвращает Stream
Stream<Integer> stream = numbers.stream()
    .filter(x -> x > 2);
// Можно продолжить:
stream.map(x -> x * 2);

// Терминальный — возвращает результат
List<Integer> list = numbers.stream()
    .filter(x -> x > 2)
    .collect(Collectors.toList());  // List, не Stream!
// Нельзя продолжить, stream закрыт

Терминальные методы (для полноты)

// Все эти методы ЗАКАНЧИВАЮТ цепь
numbers.stream().forEach(System.out::println);  // void
numbers.stream().collect(Collectors.toList());  // List
numbers.stream().reduce(0, Integer::sum);       // Integer
numbers.stream().count();                       // long
numbers.stream().max(Integer::compare);         // Optional
numbers.stream().anyMatch(x -> x > 5);          // boolean

Плюсы конвейерных методов

1. Читаемость кода

// Конвейерный подход — понятно что происходит
List<String> result = users.stream()
    .filter(u -> u.isActive())
    .map(User::getName)
    .sorted()
    .collect(Collectors.toList());

// vs Императивный подход
List<String> result = new ArrayList<>();
for (User u : users) {
    if (u.isActive()) {
        result.add(u.getName());
    }
}
Collections.sort(result);

2. Производительность (благодаря лениости)

// Обработает максимум 2 элемента (limit прерывает)
numbers.stream()
    .filter(x -> x % 2 == 0)  // Даже если есть млн элементов
    .limit(2)
    .forEach(System.out::println);

3. Параллелизм

// Просто меняем stream() на parallelStream()
numbers.parallelStream()
    .filter(x -> x > 2)
    .map(x -> x * 2)
    .collect(Collectors.toList());
// Параллельная обработка на всех потоках

Практический пример: обработка данных

public class StreamExample {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Alice", 30, "Engineer"),
            new Person("Bob", 25, "Manager"),
            new Person("Charlie", 35, "Engineer"),
            new Person("David", 28, "Designer")
        );
        
        // Конвейерная цепь
        List<String> engineers = people.stream()
            .filter(p -> "Engineer".equals(p.getRole()))  // Конвейерный
            .filter(p -> p.getAge() > 25)                  // Конвейерный
            .map(Person::getName)                          // Конвейерный
            .sorted()                                      // Конвейерный
            .collect(Collectors.toList());                 // Терминальный
        
        System.out.println(engineers);  // [Alice, Charlie]
    }
}

class Person {
    private String name;
    private int age;
    private String role;
    // getters...
}

Итог

Конвейерный метод в Stream:

  • Возвращает Stream для продолжения цепи
  • Работает лениво (отложенные вычисления)
  • Примеры: filter, map, sorted, distinct, limit, skip
  • Позволяет писать функциональный код на Java
  • Оптимизирует производительность за счёт short-circuit операций

Конвейерные методы — это сердце Stream API в Java, позволяя писать декларативный, читаемый и эффективный код.

Что такое конвейерный метод в Stream? | PrepBro