Понимание Spliterator, Collector и Stream в Java 8
Мне трудно понять интерфейс Stream
в Java 8, особенно там, где это связано с Spliterator
и Collector
. Моя проблема в том, что я просто не могу понять интерфейсы Spliterator
и Collector
, и в результате интерфейс Stream
все еще несколько неясен для меня.
Что такое Spliterator
и Collector
, и как я могу их использовать? Если я готов написать свой собственный Spliterator
или Collector
(и, возможно, мой собственный Stream
в этом процессе), что мне делать и не делать?
Я читал несколько примеров, разбросанных по сети, но поскольку все здесь является новым и подверженным изменениям, примеры и руководства по-прежнему очень скудны.
Ответы
Ответ 1
Вам почти наверняка никогда не придется иметь дело с Spliterator
как пользователь; это необходимо только в том случае, если вы пишете типы Collection
, а также намереваетесь оптимизировать на них параллельные операции.
Для того, что стоит, Spliterator
является способом работы над элементами коллекции таким образом, что легко отделить часть коллекции, например. потому что вы распараллеливаете и хотите, чтобы один поток работал над одной частью коллекции, один поток работал с другой частью и т.д.
По существу, вы никогда не должны сохранять значения типа Stream
в переменной. Stream
похожа на Iterator
, поскольку это одноразовый объект, который вы почти всегда будете использовать в беглой цепочке, как в примере Javadoc:
int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
.sum();
Collector
- наиболее обобщенная, абстрактная возможная версия операции "уменьшения" a la map/reduce; в частности, он должен поддерживать шаги по распараллеливанию и завершению. Примеры Collector
включают:
- например.
Collectors.reducing(0, (x, y) -> x + y)
- Добавление StringBuilder, например.
Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
Ответ 2
Spliterator
в основном означает "расщепляемый итератор".
Один поток может перемещать/обрабатывать весь сам Spliterator, но Spliterator также имеет метод trySplit()
, который "отделит" раздел для кого-то другого (как правило, другого потока) для обработки - оставив текущий разделитель с меньше работа.
Collector
объединяет спецификацию функции reduce
(из-за славы отображения карты), с начальным значением и значением для объединения двух результатов (что позволяет объединить результаты из разделенных потоков работы).
Например, у самого базового коллектора будет начальная вауа из 0, добавьте целое число в существующий результат и "объединит" два результата, добавив их. Таким образом суммируя разделенный поток целых чисел.
См:
Ответ 3
Ниже приведены примеры использования предопределенных коллекционеров для выполнения общих изменяемых задач сокращения:
// Accumulate names into a List
List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
// Accumulate names into a TreeSet
Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
// Convert elements to strings and concatenate them, separated by commas
String joined = things.stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
// Compute sum of salaries of employee
int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));
// Group employees by department
Map<Department, List<Employee>> byDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
// Compute sum of salaries by department
Map<Department, Integer> totalByDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
// Partition students into passing and failing
Map<Boolean, List<Student>> passingFailing =
students.stream()
.collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
Ответ 4
Как стартер знакомиться с функциональным программированием в google guava, где используются традиционные итераторы. Изучите, как объекты фильтруются, трансформируются и собираются. Затем перейдите в java 8.