Разница между Итератором и Сплитератором в Java8
Я узнал, изучая это Parallelism
это главное преимущество Spliterator
,
Это может быть основной вопрос, но может ли кто-нибудь объяснить мне основные различия между Iterator
а также Spliterator
и привести несколько примеров?
2 ответа
Имена для меня очень понятны. Spliterator
== Splittable Iterator: он может разделить некоторый источник, и он может повторить это тоже. Это вроде имеет такую же функциональность, как Iterator
, но с дополнительным, что он может потенциально разделить на несколько частей, это то, что trySplit
для. Расщепление необходимо для параллельной обработки.
Iterator
имеет всегда неизвестный размер, вы можете проходить элементы только через hasNext/next
; Spliterator
может предоставить размер (таким образом улучшая другие операции слишком внутренне); либо точный через getExactSizeIfKnown
или приблизительный через estimateSize
,
С другой стороны, tryAdvance
это что hasNext/next
из Iterator
, но это единственный метод, гораздо проще рассуждать об ИМО. С этим связано forEachRemaining
который в реализации по умолчанию делегирует tryAdvance
, но так не должно быть всегда. (увидеть ArrayList
например)
Spliterator также является "более умным" итератором, благодаря своим внутренним свойствам, таким как DISTINCT
или же SORTED
и т. д. (что необходимо правильно указать при реализации Spliterator
). Эти флаги используются внутри системы для отключения ненужных операций, также называемых оптимизациями, как, например, эта:
someStream().map(x -> y).count();
Поскольку размер не изменяется в случае потока, map
может быть пропущен полностью, так как все, что мы делаем, это считаем.
Вы можете создать Spliterator вокруг Iterator, если вам потребуется, с помощью:
Spliterators.spliteratorUnknownSize(yourIterator, properties)
Iterator
это простое представление серии элементов, которые могут быть повторены.
например:
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
Iterator<String> i = list.iterator();
i.next();
i.forEachRemaining(System.out::println);
#output
Banana
Orange
Spliterator
может использоваться для разделения данного набора элементов на несколько наборов, чтобы мы могли выполнять какие-либо операции / вычисления над каждым набором в разных потоках независимо, возможно, используя преимущества параллелизма. Он выполнен в виде параллельного аналога Iterator. Помимо коллекций, источником элементов, охватываемых Spliterator, может быть, например, массив, канал ввода-вывода или функция генератора.
Есть 2 основных метода в Spliterator
интерфейс.
- tryAdvance() и forEachRemaining()
С помощью tryAdvance() мы можем просматривать базовые элементы один за другим (точно так же, как Iterator.next()). Если остающийся элемент существует, этот метод выполняет действие потребителя над ним, возвращая true; иначе возвращает ложь.
Для последовательного массового обхода мы можем использовать forEachRemaining():
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
Spliterator<String> s = list.spliterator();
s.tryAdvance(System.out::println);
System.out.println(" --- bulk traversal");
s.forEachRemaining(System.out::println);
System.out.println(" --- attempting tryAdvance again");
boolean b = s.tryAdvance(System.out::println);
System.out.println("Element exists: "+b);
Выход:
Apple
--- bulk traversal
Banana
Orange
--- attempting tryAdvance again
Element exists: false
- Spliterator trySplit ()
Разбивает этот сплитератор на два и возвращает новый:
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
Spliterator<String> s = list.spliterator();
Spliterator<String> s1 = s.trySplit();
s.forEachRemaining(System.out::println);
System.out.println("-- traversing the other half of the spliterator --- ");
s1.forEachRemaining(System.out::println);
Выход:
Banana
Orange
-- traversing the other half of the spliterator ---
Apple
Идеальный метод trySplit должен делить его элементы ровно пополам, обеспечивая сбалансированные параллельные вычисления.
Процесс разделения также называется "разделением" или "разложением".