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

Из каких частей состоит Stream

2.3 Middle🔥 151 комментариев
#Брокеры сообщений

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

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

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

Из каких частей состоит Stream?

Stream API (введён в Java 8) — это функциональный подход к обработке данных. Stream состоит из трёх ключевых частей: источник данных, промежуточные операции и терминальная операция.

1. Источник данных (Data Source)

Это начало потока — коллекция, массив или другой источник данных:

// Из коллекции
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> stream1 = names.stream();

// Из массива
int[] numbers = {1, 2, 3, 4, 5};
IntStream stream2 = Arrays.stream(numbers);

// Из Stream.of()
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);

// Из диапазона
IntStream stream4 = IntStream.range(1, 10); // [1, 2, ..., 9]
IntStream stream5 = IntStream.rangeClosed(1, 10); // [1, 2, ..., 10]

// Из файла
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    // ...
}

// Бесконечный Stream
Stream<Integer> infinite = Stream.iterate(0, n -> n + 1);
Stream<Double> randomNumbers = Stream.generate(Math::random);

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

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

map() — преобразование элементов

List<String> names = Arrays.asList("alice", "bob", "charlie");
List<String> uppercase = names.stream()
    .map(String::toUpperCase) // Преобразуем в верхний регистр
    .collect(Collectors.toList());
// Результат: [ALICE, BOB, CHARLIE]

filter() — фильтрация элементов

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evens = numbers.stream()
    .filter(n -> n % 2 == 0) // Оставляем только чётные
    .collect(Collectors.toList());
// Результат: [2, 4, 6]

flatMap() — плоское отображение

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

List<Integer> flat = matrix.stream()
    .flatMap(List::stream) // Разворачиваем вложенные списки
    .collect(Collectors.toList());
// Результат: [1, 2, 3, 4, 5, 6]

distinct() — уникальные элементы

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4);
List<Integer> unique = numbers.stream()
    .distinct()
    .collect(Collectors.toList());
// Результат: [1, 2, 3, 4]

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<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> byLength = names.stream()
    .sorted(Comparator.comparing(String::length))
    .collect(Collectors.toList());
// Результат: [Bob, Alice, Charlie]

limit() и skip() — пагинация

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

// Первые 5 элементов
List<Integer> first5 = numbers.stream()
    .limit(5)
    .collect(Collectors.toList());
// Результат: [1, 2, 3, 4, 5]

// Пропустить первые 2, взять следующие 5
List<Integer> paginated = numbers.stream()
    .skip(2) // Пропускаем [1, 2]
    .limit(5) // Берём 5
    .collect(Collectors.toList());
// Результат: [3, 4, 5, 6, 7]

peek() — просмотр элементов (для отладки)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = numbers.stream()
    .filter(n -> n > 2)
    .peek(n -> System.out.println("After filter: " + n))
    .map(n -> n * 2)
    .peek(n -> System.out.println("After map: " + n))
    .collect(Collectors.toList());

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

Это операции, которые завершают обработку потока и возвращают результат (НЕ Stream):

collect() — сбор результатов

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

// В List
List<Integer> list = numbers.stream()
    .filter(n -> n > 2)
    .collect(Collectors.toList());

// В Set
Set<Integer> set = numbers.stream()
    .collect(Collectors.toSet());

// В Map
Map<Integer, String> map = numbers.stream()
    .collect(Collectors.toMap(
        n -> n,
        n -> "Number: " + n
    ));

// В String
String joined = numbers.stream()
    .map(String::valueOf)
    .collect(Collectors.joining(", "));
// Результат: "1, 2, 3, 4, 5"

forEach() — итерирование

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
    .filter(n -> n.length() > 3)
    .forEach(System.out::println);
// Output: Alice
//         Charlie

reduce() — свёртка/агрегация

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

// Сумма
int sum = numbers.stream()
    .reduce(0, Integer::sum);
// Результат: 15

// Произведение
int product = numbers.stream()
    .reduce(1, (a, b) -> a * b);
// Результат: 120

// Без initial value
Optional<Integer> sumOptional = numbers.stream()
    .reduce(Integer::sum);
// Результат: Optional[15]

min() / max() — минимум/максимум

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

Optional<Integer> min = numbers.stream()
    .min(Comparator.naturalOrder());
// Результат: Optional[1]

Optional<Integer> max = numbers.stream()
    .max(Comparator.naturalOrder());
// Результат: Optional[9]

count() — количество элементов

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

long count = numbers.stream()
    .filter(n -> n > 3)
    .count();
// Результат: 3

findFirst() / findAny() — поиск элемента

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

Optional<Integer> first = numbers.stream()
    .filter(n -> n > 2)
    .findFirst();
// Результат: Optional[3]

Optional<Integer> any = numbers.stream()
    .filter(n -> n > 2)
    .findAny(); // В последовательном потоке = findFirst()

anyMatch() / allMatch() / noneMatch() — проверка условия

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

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<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Источник (List) → Промежуточные операции → Терминальная операция
List<Integer> result = numbers.stream()        // Источник
    .filter(n -> n > 3)                        // Промежуточная: filter
    .map(n -> n * 2)                          // Промежуточная: map
    .sorted()                                  // Промежуточная: sorted
    .distinct()                                // Промежуточная: distinct
    .collect(Collectors.toList());            // Терминальная: collect

// Результат: [8, 10, 12, 14, 16, 18, 20]

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

Структура Stream позволяет выполнять операции только когда это необходимо:

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

Stream<Integer> stream = numbers.stream()
    .filter(n -> {
        System.out.println("Filtering: " + n);
        return n > 2;
    })
    .map(n -> {
        System.out.println("Mapping: " + n);
        return n * 2;
    });

// На данном этапе ничего не печатается — промежуточные операции ленивые!

List<Integer> result = stream.collect(Collectors.toList());
// Теперь печатается:
// Filtering: 1
// Filtering: 2
// Filtering: 3
// Mapping: 3
// Filtering: 4
// Mapping: 4
// Filtering: 5
// Mapping: 5

Итоговая структура Stream

[Источник] → [Промежуточные операции] → [Терминальная операция] → Результат
  ↓              ↓                              ↓                     ↓
- List         - map()                      - collect()            - List
- Array        - filter()                   - forEach()            - Set
- Stream.of()  - flatMap()                  - reduce()             - Map
- Range        - distinct()                 - count()              - int/long
- File         - sorted()                   - min/max()            - Optional
- generate()   - limit/skip()               - find*()              - void
- iterate()    - peek()                     - match()              - boolean

Ключевая концепция: Stream = Источник + Промежуточные операции (ленивые) + Одна терминальная операция (выполняет вычисления).