Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Коллекторы (Collectors) в Java Stream API
Collectors - это инструмент для сбора результатов потока (stream) в различные контейнеры. Они используются с методом .collect() и предоставляют мощные способы трансформации и агрегирования данных.
1. toList() и toSet()
Базовые коллекторы для сбора в коллекции:
List<String> names = Stream.of("John", "Jane", "Bob")
.collect(Collectors.toList());
Set<String> uniqueNames = Stream.of("John", "Jane", "John")
.collect(Collectors.toSet());
// Java 16+ - неизменяемые коллекции
List<String> immutableList = Stream.of("a", "b", "c")
.collect(Collectors.toUnmodifiableList());
2. toMap()
Сбор в Map:
Map<UUID, String> userMap = users.stream()
.collect(Collectors.toMap(
User::getId, // Key extractor
User::getName // Value extractor
));
// С дополнительной логикой
Map<String, Integer> userCount = users.stream()
.collect(Collectors.toMap(
User::getName,
user -> 1,
Integer::sum // Если есть дубликаты - суммируем
));
3. groupingBy()
Группировка элементов по ключу:
// Группировка по отделу
Map<String, List<User>> byDepartment = users.stream()
.collect(Collectors.groupingBy(User::getDepartment));
// Result: {IT: [User1, User2], HR: [User3]}
// Группировка с подсчётом
Map<String, Long> deptCount = users.stream()
.collect(Collectors.groupingBy(
User::getDepartment,
Collectors.counting()
));
// Result: {IT: 2, HR: 1}
// Многоуровневая группировка
Map<String, Map<String, List<User>>> nested = users.stream()
.collect(Collectors.groupingBy(
User::getDepartment,
Collectors.groupingBy(User::getTeam)
));
4. partitioningBy()
Разбиение на две группы по условию:
// Разделить на senior и junior
Map<Boolean, List<User>> seniors = users.stream()
.collect(Collectors.partitioningBy(
user -> user.getYearsOfExperience() >= 5
));
// Result: {true: [Senior1, Senior2], false: [Junior1]}
// С подсчётом
Map<Boolean, Long> seniorCount = users.stream()
.collect(Collectors.partitioningBy(
user -> user.getYearsOfExperience() >= 5,
Collectors.counting()
));
5. joining()
Объединение строк с разделителем:
String names = users.stream()
.map(User::getName)
.collect(Collectors.joining(", "));
// Result: "John, Jane, Bob"
// С префиксом и суффиксом
String formatted = users.stream()
.map(User::getName)
.collect(Collectors.joining(", ", "[", "]"));
// Result: "[John, Jane, Bob]"
6. summarizingInt(), summarizingLong(), summarizingDouble()
Статистика по числовым значениям:
IntSummaryStatistics stats = users.stream()
.collect(Collectors.summarizingInt(User::getAge));
System.out.println("Count: " + stats.getCount());
System.out.println("Sum: " + stats.getSum());
System.out.println("Average: " + stats.getAverage());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());
7. averaging()
Вычисление среднего:
double avgAge = users.stream()
.collect(Collectors.averagingInt(User::getAge));
double avgSalary = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
8. summingInt(), summingLong(), summingDouble()
Сумма элементов:
int totalAge = users.stream()
.collect(Collectors.summingInt(User::getAge));
long totalSalary = employees.stream()
.collect(Collectors.summingLong(Employee::getSalary));
9. counting()
Подсчёт элементов:
long userCount = users.stream()
.collect(Collectors.counting());
// Эквивалентно:
long count = users.stream().count();
10. maxBy() и minBy()
Нахождение максимума и минимума:
Optional<User> oldestUser = users.stream()
.collect(Collectors.maxBy(
Comparator.comparingInt(User::getAge)
));
Optional<User> youngestUser = users.stream()
.collect(Collectors.minBy(
Comparator.comparingInt(User::getAge)
));
11. mapping()
Трансформация элементов в collector:
// Получить все имена в лист с группировкой по отделу
Map<String, List<String>> namesByDept = users.stream()
.collect(Collectors.groupingBy(
User::getDepartment,
Collectors.mapping(User::getName, Collectors.toList())
));
// Получить уникальные имена
Map<String, Set<String>> uniqueNamesByDept = users.stream()
.collect(Collectors.groupingBy(
User::getDepartment,
Collectors.mapping(User::getName, Collectors.toSet())
));
12. flatMapping()
Развёртывание вложенных потоков:
// Если User имеет List<String> skills
Map<String, Set<String>> skillsByDept = users.stream()
.collect(Collectors.groupingBy(
User::getDepartment,
Collectors.flatMapping(
user -> user.getSkills().stream(),
Collectors.toSet()
)
));
13. reducing()
Редукция потока к одному значению:
// Сумма зарплат
Optional<BigDecimal> totalSalary = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add));
// Конкатенация строк
String allNames = users.stream()
.map(User::getName)
.collect(Collectors.reducing("", (a, b) -> a + ", " + b));
14. Custom Collector
Создание собственного collector:
public class CustomCollectors {
public static <T> Collector<T, ?, LinkedList<T>> toLinkedList() {
return Collector.of(
LinkedList::new, // Supplier
LinkedList::add, // Accumulator
(list1, list2) -> { // Combiner
list1.addAll(list2);
return list1;
}
);
}
}
// Использование
LinkedList<User> linkedList = users.stream()
.collect(CustomCollectors.toLinkedList());
15. Сложный пример - аналитика
@Data
public class Employee {
private String name;
private String department;
private double salary;
private int yearsExperience;
}
// Анализ по отделам
var analysis = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.collectingAndThen(
Collectors.toList(),
list -> new DepartmentAnalysis(
list.size(),
list.stream().mapToDouble(Employee::getSalary).average().orElse(0),
list.stream().mapToInt(Employee::getYearsExperience).max().orElse(0)
)
)
));
@Data
class DepartmentAnalysis {
private int employeeCount;
private double avgSalary;
private int maxYearsExperience;
}
Best Practices
✓ Используйте встроенные collectors для стандартных операций ✓ Комбинируйте collectors для сложных трансформаций ✓ Используйте collectingAndThen для финальной обработки ✓ Помните о производительности при больших потоках ✓ Используйте parallelStream() с care (потокобезопасность) ✓ Предпочитайте collectors вместо forEach с побочными эффектами ✓ Документируйте сложные комбинации collectors ✓ Тестируйте edge cases (пустые потоки, null значения)
Collectors - мощный инструмент для функционального программирования в Java.