Понимание 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.