Приведи пример терминальной операции
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Приведи пример терминальной операции
Терминальная операция (Terminal Operation) в Stream API — это операция, которая завершает поток и возвращает конечный результат. После терминальной операции больше нельзя работать со Stream.
Что такое терминальная операция
Операции в Stream API делятся на две категории:
-
Промежуточные (Intermediate): возвращают Stream
map(),filter(),flatMap(),distinct(),sorted()
-
Терминальные (Terminal): возвращают конкретный результат
collect(),forEach(),reduce(),findFirst(),count(),anyMatch()
Примеры терминальных операций
1. collect() — самая важная
List<String> names = Stream.of("Alice", "Bob", "Charlie")
.filter(name -> name.length() > 3)
.collect(Collectors.toList()); // Терминальная
System.out.println(names); // [Alice, Charlie]
// Более сложный пример: группировка
Map<Integer, List<String>> byLength = Stream.of("a", "bb", "ccc", "dd")
.collect(Collectors.groupingBy(String::length));
// Результат:
// {1=[a], 2=[bb, dd], 3=[ccc]}
// Создание Set вместо List
Set<String> uniqueNames = Stream.of("Alice", "Bob", "Alice")
.collect(Collectors.toSet());
System.out.println(uniqueNames); // [Alice, Bob]
2. forEach() — для выполнения действия
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.filter(n -> n % 2 == 0)
.forEach(n -> System.out.println(n)); // Терминальная
// Вывод:
// 2
// 4
3. reduce() — для объединения элементов
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Суммирование
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b); // Терминальная
System.out.println(sum); // 15
// Найти максимум
int max = numbers.stream()
.reduce(Integer.MIN_VALUE, (a, b) -> a > b ? a : b);
System.out.println(max); // 5
// Optional версия (без начального значения)
Optional<Integer> sum = numbers.stream()
.reduce((a, b) -> a + b); // Терминальная
if (sum.isPresent()) {
System.out.println("Sum: " + sum.get()); // Sum: 15
}
4. findFirst() / findAny() — поиск элемента
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Optional<String> first = names.stream()
.filter(name -> name.startsWith("B"))
.findFirst(); // Терминальная - возвращает Optional
if (first.isPresent()) {
System.out.println(first.get()); // Bob
}
// findAny() может быть быстрее в параллельных streams
Optional<String> any = names.parallelStream()
.filter(name -> name.startsWith("A"))
.findAny(); // Терминальная
System.out.println(any.get()); // Alice
5. count() — количество элементов
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
long evenCount = numbers.stream()
.filter(n -> n % 2 == 0)
.count(); // Терминальная
System.out.println(evenCount); // 5
6. anyMatch() / allMatch() / noneMatch()
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// anyMatch — есть ли хотя бы один?
boolean hasEven = numbers.stream()
.anyMatch(n -> n % 2 == 0); // Терминальная
System.out.println(hasEven); // true
// allMatch — все ли?
boolean allPositive = numbers.stream()
.allMatch(n -> n > 0); // Терминальная
System.out.println(allPositive); // true
// noneMatch — ни один?
boolean noNegative = numbers.stream()
.noneMatch(n -> n < 0); // Терминальная
System.out.println(noNegative); // true
7. min() / max() — минимум и максимум
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);
Optional<Integer> min = numbers.stream()
.min(Integer::compareTo); // Терминальная
Optional<Integer> max = numbers.stream()
.max(Integer::compareTo); // Терминальная
System.out.println("Min: " + min.get()); // Min: 1
System.out.println("Max: " + max.get()); // Max: 9
Практический пример: обработка данных пользователей
public class User {
private String name;
private int age;
private String email;
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// getters...
}
// Данные
List<User> users = Arrays.asList(
new User("Alice", 25, "alice@example.com"),
new User("Bob", 30, "bob@example.com"),
new User("Charlie", 35, "charlie@example.com"),
new User("Diana", 28, "diana@example.com")
);
// Пример 1: найти первого пользователя старше 25
Optional<User> firstOlder = users.stream()
.filter(u -> u.getAge() > 25)
.findFirst(); // Терминальная
// Пример 2: все ли пользователи старше 20?
boolean allAdults = users.stream()
.allMatch(u -> u.getAge() > 20); // Терминальная
System.out.println(allAdults); // true
// Пример 3: собрать имена пользователей старше 28
List<String> names = users.stream()
.filter(u -> u.getAge() > 28)
.map(User::getName)
.collect(Collectors.toList()); // Терминальная
System.out.println(names); // [Bob, Charlie]
// Пример 4: групп по возрасту
Map<Integer, List<User>> byAge = users.stream()
.collect(Collectors.groupingBy(User::getAge)); // Терминальная
// Пример 5: среднее значение возраста
double avgAge = users.stream()
.mapToInt(User::getAge)
.average() // Терминальная
.orElse(0);
System.out.println("Average age: " + avgAge); // Average age: 29.5
Важные моменты
1. Stream не может использоваться после терминальной операции:
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
stream.filter(n -> n > 1)
.collect(Collectors.toList()); // Терминальная - Stream закрыт
stream.forEach(System.out::println); // ОШИБКА! Stream already closed
2. Терминальная операция запускает обработку Stream:
// Это ничего не выполнит (нет терминальной операции)
Arrays.asList(1, 2, 3).stream()
.filter(n -> {
System.out.println("Filtering: " + n); // Не выведется
return n > 1;
});
// А это выполнит
Arrays.asList(1, 2, 3).stream()
.filter(n -> {
System.out.println("Filtering: " + n); // Выведется
return n > 1;
})
.collect(Collectors.toList()); // Терминальная - запускает обработку
3. Порядок важен для производительности:
// Неэффективно: считает ВСЕ элементы, затем берёт первый
Optional<Integer> first = numbers.stream()
.filter(n -> n > 5)
.findFirst();
// Лучше: берёт первый и останавливается
Optional<Integer> first = numbers.stream()
.filter(n -> {
System.out.println("Checking: " + n);
return n > 5;
})
.findFirst();
// Вывод: только первые несколько элементов, не все!
Итоги
Терминальные операции:
- Завершают Stream и возвращают конечный результат
- Запускают обработку (ленивые вычисления)
- Основные:
collect(),forEach(),reduce(),findFirst(),count(),anyMatch() - Нельзя использовать Stream после терминальной операции
- Порядок операций важен для производительности