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

Какие знаешь коллекторы?

2.0 Middle🔥 171 комментариев
#Базы данных и SQL

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

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

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

Коллекторы (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.

Какие знаешь коллекторы? | PrepBro