Комментарии (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 = Источник + Промежуточные операции (ленивые) + Одна терминальная операция (выполняет вычисления).