Понимание 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()
Этот метод позволяет разделить набор данных на множество небольших наборов по одной или другой критерий (размер файла, количество строк и т. д.).