Пример Java ArrayList spliterator()

Начиная с Java 8, Spliterators — это особый тип итератора, который поддерживает параллельную итерацию частей источника, таких как массив, набор, список или канал ввода-вывода. Хотя Spliterators в основном поддерживают параллельное программирование, мы можем использовать Spliterator, даже если мы не будем использовать параллельное выполнение.

ArrayList.spliterator() возвращает экземпляр Spliterator, который является последним связываемым и быстро завершается сбоем.

  • Позднее связывание означает, что привязка к источнику данных происходит в точке первого обхода или первого разделения, а не во время создания Spliterator.
  • Fail-fast означает, что он выдает исключение ConcurrentModificationException, если обнаруживает, что источник данных был структурно изменен после его создания. Структурные изменения включают добавление, удаление или обновление элементов, что может нарушить согласованность просматриваемых данных.
 // Получить Spliterator из ArrayListSpliterator spliterator = arraylist.spliterator();// Преобразовать Spliterator в параллельный поток и обрабатывать элементы параллельноStreamSupport.stream(spliterator, true).forEach(System.out::println);

1. Метод ArrayList spliterator()

В случае ArrayList метод spliterator() возвращает экземпляр класса ArrayListSpliterator, который находится во внутреннем классе ArrayList и реализует интерфейс Spliterator.

public Spliterator<E> spliterator() {return new ArrayListSpliterator<>(this, 0, -1, 0);}static final class ArrayListSpliterator<E> implements Spliterator<E> {//implementation}

Сплиттератор, возвращаемый ArrayList, следующий:

  • ORDERED – указывает, что элементы имеют определенный порядок при обходе и разбиении.
  • SORTED – означает, что элементы следуют предопределенному порядку сортировки.
  • SUBSIZED – указывает, что этот и любой последующий результирующий Spliterator имеют РАЗМЕР. Здесь SIZED означает, что Spliterator был создан из источника с известным размером.

2. Пример ArrayList spliterator()

Spliterator может использоваться для многих вариантов использования. Некоторые из вариантов использования обсуждаются в приведенных ниже примерах.

2.1. TryAdvance(): итерация одного элемента за раз

Программа Java для итерации одного элемента за раз с использованием spliterator. Это эквивалентно методу iterator.next() из интерфейса Iterator.

ArrayList<Integer> digits = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));Spliterator<Integer> sItr = digits.spliterator();sItr.tryAdvance( d -> System.out.println( d ) );sItr.tryAdvance( d -> System.out.println( d ) );sItr.tryAdvance( d -> System.out.println( d ) );

Вывод программы.

123

2.2. forEachRemaining(): перебрать все элементы

Программа Java для итерации всех элементов и выполнения действия над ними. Это эквивалентно методу iterator.hasNext() вместе с iterator.next() в цикле.

ArrayList<Integer> digits = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));Spliterator<Integer> sItr = digits.spliterator();sItr.tryAdvance( d -> System.out.println( d ) ); //1sItr.tryAdvance( d -> System.out.println( d ) ); //2sItr.forEachRemaining( d -> System.out.println( d ) ); //3,4,5,6

Вывод программы.

 123456

2.3. TrySplit(): параллельная обработка

Если вы работаете над параллельным приложением и список содержит большое количество элементов, то будет хорошей идеей разделить список на две части и обрабатывать их параллельно.

Метод trySplit() разделяет текущий spliterator на два и возвращает новый. Элементы, на которые он указывает, делятся на два равных списка.

Имейте в виду, что по умолчанию отдельный Spliterator не является потокобезопасным. Создание различных потоков и передача экземпляров Spliterator является обязанностью кода приложения.

ArrayList<Integer> digits = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));Spliterator<Integer> sItr1 = digits.spliterator();Spliterator<Integer> sItr2 = sItr1.trySplit();System.out.println(sItr1.getExactSizeIfKnown()); //3sItr1.forEachRemaining( d -> System.out.println( d ) ); //4,5,6System.out.println("===========");System.out.println(sItr2.getExactSizeIfKnown()); //3sItr2.forEachRemaining( d -> System.out.println( d ) ); //1,2,3 

Вывод программы.

3456===========3123

2.4 Пакетная обработка

Spliterator можно использовать для массовых операций обработки, например, для применения пакетной операции к подмножеству элементов.

import java.util.ArrayList;import java.util.List;import java.util.Spliterator;public class BatchProcessingExample {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("One");list.add("Two");list.add("Three");list.add("Four");Spliterator<String> spliterator = list.spliterator();int batchSize = 2;List<String> batch = new ArrayList<>(batchSize);while(spliterator.tryAdvance(batch::add)) {if(batch.size() == batchSize) {processBatch(batch);batch.clear();}}if(!batch.isEmpty()) {processBatch(batch);}}private static void processBatch(List<String> batch) {System.out.println("Processing batch: " + batch);}}

2.5. Разделение рабочей нагрузки для рекурсивных алгоритмов

Spliterator можно разделить и использовать в рекурсивных алгоритмах, например, для реализации параллельной версии алгоритма «разделяй и властвуй».

import java.util.ArrayList;import java.util.List;import java.util.Spliterator;public class RecursiveSplittingExample {public static void main(String[] args) {List<Integer> list = new ArrayList<>();for(int i = 1; i <= 16; i++) {list.add(i);}Spliterator<Integer> spliterator = list.spliterator();parallelSum(spliterator);}private static void parallelSum(Spliterator<Integer> spliterator) {long size = spliterator.estimateSize();if(size <= 4) { // Base case for the recursive splittingspliterator.forEachRemaining(element -> System.out.println(Thread.currentThread().getName() + " - " + element));return;}Spliterator<Integer> split = spliterator.trySplit();if(split != null) {Thread leftThread = new Thread(() -> parallelSum(spliterator));Thread rightThread = new Thread(() -> parallelSum(split));leftThread.start();rightThread.start();try {leftThread.join();rightThread.join();} catch(InterruptedException e) {Thread.currentThread().interrupt();}}}}

3. Разница между итератором и сплиттератором

Итератор Сплиттератор
Начиная с Java 1.2. Начиная с Java 8.
Может использоваться для итерации всех классов коллекций. Может использоваться для итерации массива, потока, списка и набора. Невозможно с map.
Не поддерживает параллельную обработку. Поддерживает параллельную обработку.

Вот и все о методе ArrayList spliterator() в Java.

Читать далее:

Руководство по Java ArrayList
ArrayList Java Документация
Сплиттератор Java Документация

Прокрутить вверх