Что принимает метод collectors в Java и какие коллекторы существуют
Что проверяют
Знаете ли вы, что результат собирает не мифический метод collectors, а терминальная операция collect, и умеете ли назвать больше трёх коллекторов. Заодно смотрят, понимаете ли, из чего коллектор состоит: отсюда ответ про параллельную сборку.
Как отвечать
Поправьте формулировку спокойно: Collectors это утилитный класс с фабричными методами, а принимает коллектор операция Stream.collect. Сам Collector<T, A, R> описан четырьмя функциями и набором характеристик: supplier создаёт накопитель, accumulator кладёт в него элемент, combiner сливает два накопителя (именно он делает возможной параллельную сборку), finisher превращает накопитель в результат.
Готовые коллекторы удобно называть группами:
- в коллекцию:
toList,toSet,toMap,toCollection(TreeSet::new)и неизменяемые варианты вродеtoUnmodifiableList; - в одно значение:
joining,counting,summingInt,averagingDouble,summarizingInt,minBy,maxBy,reducing; - разбиение:
groupingByпо ключу иpartitioningByпо предикату, оба принимают вложенный коллектор; - обёртки над другим коллектором:
mapping,filtering,flatMapping,collectingAndThen,teeing.
Сильный ход это показать вложенность: видно, что коллектор кирпич, а не элемент списка констант:
Map<String, Long> byCity = users.stream()
.collect(Collectors.groupingBy(User::getCity, Collectors.counting()));Где спотыкаются
Забывают про дубликаты ключа в toMap: метод бросает IllegalStateException, и всплывает это не в тесте, а на бою. Нужна форма с функцией слияния. Вторая ловушка того же метода: значение null даёт NullPointerException, тогда как groupingBy такие элементы переживает.
Второе: считают результат toList гарантированно изменяемым списком. Контракт этого не обещает, и код, дописывающий элемент в собранный список, однажды падает. Нужен изменяемый, просите его явно через toCollection(ArrayList::new).
Третье: набивают общий контейнер руками в forEach на параллельном стриме. Без слияния накопителей это гонка и потерянные элементы. Смысл collect в том, что каждый поток набирает свой накопитель, а объединение описано отдельной функцией.