Понимание Spliterator, Collector и Stream в Java 8

у меня возникли проблемы с пониманием Stream интерфейс в Java 8, особенно там, где это связано с Spliterator и Collector интерфейсы. Моя проблема заключается в том, что я просто не могу понять Spliterator и Collector интерфейсы, и в результате Stream интерфейс все еще несколько неясен для меня.

что такое Spliterator и Collector, а как я могу их использовать? Если я хочу написать свой собственный Spliterator или Collector (и, вероятно, мой собственный Stream в этом процессе), что я должен делать и не делать?

Я прочитал несколько примеров, разбросанных по всему интернету, но поскольку все здесь по-прежнему новое и подвержено изменениям, примеры и учебные пособия по-прежнему очень редки.

4 ответов


вам почти наверняка никогда не придется иметь дело с Spliterator как пользователь; это должно быть необходимо, только если вы пишете Collection типы себя и и намереваясь оптимизировать распараллеленные операции над ними.

для чего это стоит, a 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)

Spliterator в основном означает "разбитый итератор".

один поток может пересекать / обрабатывать весь Spliterator сам, но Spliterator также имеет метод trySplit() который "отделит" Раздел для кого-то другого (как правило, другого потока) для обработки-оставляя текущий spliterator с меньшей работой.

Collector объединяет спецификацию a reduce function (of map-reduce fame), с начальным значением и значением для объединения двух результатов (что позволяет результаты от потоков Spliterated работы, должны быть объединены.)

например, самый базовый коллектор будет иметь начальный vaue 0, добавить целое число в существующий результат и "объединить" два результата, добавив их. Таким образом, подводя spliterated поток целых чисел.

посмотреть:


ниже приведены примеры использования предопределенных коллекторов для выполнения общих изменяемых задач сокращения:

 // 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));

интерфейс Spliterator - является основной особенностью потоки.

на stream() и parallelStream() методы по умолчанию представлены в Collection интерфейс. Эти методы используют Spliterator через вызов spliterator():

...

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

...

Spliterator-это внутренний итератор, который разбивает поток на более мелкие части. Эти более малые части можно обрабатывать внутри параллельный.

среди других методов есть два наиболее важных для понимания Spliterator:

  • boolean tryAdvance(Consumer<? super T> action) В отличие от Iterator, она пытается выполнить операцию со следующим элементом. Если операция выполнена успешно, метод возвращает true. В противном случае возвращает false - это означает, что отсутствует элемент или конец поток.

  • Spliterator<T> trySplit() Этот метод позволяет разделить набор данных на множество небольших наборов по одной или другой критерий (размер файла, количество строк и т. д.).