Интерфейс Spliterator<T>
- Параметры типа:
-
T- тип элементов, возвращаемых этим Spliterator
- Все известные подинтерфейсы:
-
Spliterator.OfDouble,Spliterator.OfInt,Spliterator.OfLong,Spliterator.OfPrimitive<T,T_CONS,T_SPLITR>
- Все известные реализующие классы:
-
Spliterators.AbstractDoubleSpliterator,Spliterators.AbstractIntSpliterator,Spliterators.AbstractLongSpliterator,Spliterators.AbstractSpliterator
public interface Spliterator<T>
Объект для обхода и разбиения элементов источника. Источником элементов, охватываемых Spliterator, могут быть, например, массив, Collection, канал ввода-вывода или функция-генератор.
Spliterator может обходить элементы по отдельности (tryAdvance()) или последовательно в блоках (forEachRemaining()).
Spliterator также может отделить часть своих элементов (используя trySplit()) как другой Spliterator, который может быть использован в потенциально параллельных операциях. Операции, использующие Spliterator, который не может быть разделен или делает это очень несбалансированным или неэффективным способом, вряд ли извлекут выгоду из параллелизма. Обход и разделение исчерпывают элементы; каждый Spliterator полезен только для одного блочного вычисления.
Spliterator также сообщает набор characteristics() своей структуры, источника и элементов из ORDERED, DISTINCT, SORTED, SIZED, NONNULL, IMMUTABLE, CONCURRENT и SUBSIZED. Клиенты Spliterator могут использовать их для управления, специализации или упрощения вычислений. Например, Spliterator для Collection будет сообщать SIZED, Spliterator для Set будет сообщать DISTINCT, и Spliterator для SortedSet также будет сообщать SORTED. Характеристики сообщаются как простой объединённый набор битов. Некоторые характеристики дополнительно ограничивают поведение метода; например, если ORDERED, методы обхода должны соответствовать их документированному порядку. В будущем могут быть определены новые характеристики, поэтому реализующие не должны присваивать значения неперечисленным значениям.
Ожидается, что Spliterator, который не сообщает о IMMUTABLE или CONCURRENT , будет иметь документированную политику относительно: когда spliterator связывается с источником элементов; и обнаружения структурных помех источника элементов, обнаруженных после привязки. Spliterator с отложенной привязкой связывается с источником элементов в момент первого обхода, первого разделения или первого запроса для оценки размера, а не в момент создания Spliterator. Spliterator, который не является отложенной привязкой, связывается с источником элементов в момент создания или первого вызова любого метода. Изменения, внесённые в источник до привязки, отражаются при обходе Spliterator. После привязки Spliterator должен, по возможности, генерировать исключение ConcurrentModificationException, если обнаружит структурные помехи. Такие Spliterator называются быстродействующими. Метод блочного обхода (forEachRemaining()) Spliterator может оптимизировать обход и проверять структурные помехи после обхода всех элементов, а не проверять каждый элемент и немедленно завершать работу.
Spliterator может предоставить оценку количества оставшихся элементов через метод estimateSize(). В идеале, как отражено в характеристике SIZED, это значение точно соответствует количеству элементов, которые были бы встречены при успешном обходе. Однако, даже если значение не известно точно, оценка может быть полезна для операций, выполняемых над источником, например, для определения, предпочтительнее ли дальнейшее разделение или последовательный обход оставшихся элементов.
Несмотря на их очевидную полезность в параллельных алгоритмах, spliterators не должны быть потокобезопасными; вместо этого реализации параллельных алгоритмов, использующих spliterators, должны гарантировать, что spliterator используется только одной нитью в любой момент времени. Это обычно легко достигается с помощью последовательного потокового ограничения, что часто является естественным следствием типичных параллельных алгоритмов, которые работают с помощью рекурсивного разбиения. Нить, вызывающая trySplit(), может передать возвращённый Spliterator другой нити, которая, в свою очередь, может обходить или дополнительно разделять этот Spliterator. Поведение разделения и обхода не определено, если две или более нити работают одновременно с одним и тем же spliterator. Если исходная нить передаёт spliterator другой нити для обработки, лучше, если эта передача происходит до использования любых элементов с tryAdvance(), так как некоторые гарантии (например, точность estimateSize() для SIZED spliterators) действуют только до начала обхода.
Предоставляются специализации примитивных подтипов Spliterator для int, long и double значений. Предварительные реализации подтипа методов tryAdvance(java.util.function.Consumer) и forEachRemaining(java.util.function.Consumer) упаковывают примитивные значения в экземпляры соответствующего обертывающего класса. Такое упаковывание может подорвать любые преимущества производительности, полученные от использования специализаций примитивных типов. Чтобы избежать упаковывания, следует использовать соответствующие методы на основе примитивных типов. Например, Spliterator.OfPrimitive.tryAdvance(java.util.function.IntConsumer) и Spliterator.OfPrimitive.forEachRemaining(java.util.function.IntConsumer) следует использовать вместо Spliterator.OfInt.tryAdvance(java.util.function.Consumer) и Spliterator.OfInt.forEachRemaining(java.util.function.Consumer). Обход примитивных значений с использованием методов упаковывания tryAdvance() и forEachRemaining() не влияет на порядок, в котором значения, преобразованные в упакованные значения, встречаются.
- Примечание по API:
-
Spliterators, подобные
Iterators, предназначены для обхода элементов источника. APISpliteratorбыл разработан для поддержки эффективного параллельного обхода в дополнение к последовательному обходу, поддерживая как разбиение, так и итерацию по отдельным элементам. Кроме того, протокол доступа к элементам через Spliterator разработан таким образом, чтобы наложить меньшую нагрузку на каждый элемент, чемIterator, и избежать присущей гонки, связанной с наличием отдельных методов дляhasNext()иnext().Для изменяемых источников произвольное и недетерминированное поведение может возникнуть, если источник подвергается структурным изменениям (добавление, замена или удаление элементов) между моментом, когда Spliterator связывается со своим источником данных, и завершением обхода. Например, такие изменения приведут к произвольным, недетерминированным результатам при использовании
java.util.streamфреймворка.Структурные изменения источника можно обрабатывать следующим образом (в порядке убывания желательности):
- Источник не может подвергаться структурным изменениям.
Например, экземплярCopyOnWriteArrayListявляется неизменяемым источником. Spliterator, созданный из источника, сообщает о характеристикеIMMUTABLE. - Источник управляет одновременными изменениями.
Например, набор ключейConcurrentHashMapявляется конкурирующим источником. Spliterator, созданный из источника, сообщает о характеристикеCONCURRENT. - Изменяемый источник предоставляет Spliterator с отложенной привязкой и быстродействующий Spliterator.
Отложенная привязка сужает окно, в течение которого изменения могут повлиять на вычисления; быстродействие обнаруживает, по возможности, что структурные изменения произошли после начала обхода и генерирует исключениеConcurrentModificationException. Например,ArrayListи многие другие неконкурентныеCollectionклассы в JDK предоставляют быстродействующий Spliterator с отложенной привязкой. - Изменяемый источник предоставляет Spliterator без отложенной привязки, но быстродействующий.
Источник увеличивает вероятность генерации исключенияConcurrentModificationException, так как окно потенциальных помех больше. - Изменяемый источник предоставляет Spliterator с отложенной привязкой, но не быстродействующий.
Источник подвергает опасности произвольное, недетерминированное поведение после завершения обхода, так как изменения не обнаруживаются. - Изменяемый источник предоставляет Spliterator без отложенной привязки и не быстродействующий.
Источник увеличивает риск произвольного, недетерминированного поведения, так как необнаруженные изменения могут произойти после создания.
Пример. Вот класс (не очень полезный, кроме иллюстрации), который поддерживает массив, в котором фактические данные хранятся в чётных позициях, а не связанные данные тегов хранятся в нечётных позициях. Его Spliterator игнорирует теги.
class TaggedArray<T> { private final Object[] elements; // immutable after construction TaggedArray(T[] data, Object[] tags) { int size = data.length; if (tags.length != size) throw new IllegalArgumentException(); this.elements = new Object[2 * size]; for (int i = 0, j = 0; i < size; ++i) { elements[j++] = data[i]; elements[j++] = tags[i]; } } public Spliterator<T> spliterator() { return new TaggedArraySpliterator<>(elements, 0, elements.length); } static class TaggedArraySpliterator<T> implements Spliterator<T> { private final Object[] array; private int origin; // current index, advanced on split or traversal private final int fence; // one past the greatest index TaggedArraySpliterator(Object[] array, int origin, int fence) { this.array = array; this.origin = origin; this.fence = fence; } public void forEachRemaining(Consumer<? super T> action) { for (; origin < fence; origin += 2) action.accept((T) array[origin]); } public boolean tryAdvance(Consumer<? super T> action) { if (origin < fence) { action.accept((T) array[origin]); origin += 2; return true; } else // cannot advance return false; } public Spliterator<T> trySplit() { int lo = origin; // divide range in half int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even if (lo < mid) { // split out left half origin = mid; // reset this Spliterator's origin return new TaggedArraySpliterator<>(array, lo, mid); } else // too small to split return null; } public long estimateSize() { return (long)((fence - origin) / 2); } public int characteristics() { return ORDERED | SIZED | IMMUTABLE | SUBSIZED; } } }В качестве примера того, как фреймворк параллельных вычислений, такой как пакет
java.util.stream, использовал бы Spliterator в параллельных вычислениях, вот один способ реализовать связанную параллельную операцию forEach, которая иллюстрирует основной шаблон использования — разделение подзадач до тех пор, пока количество работы не станет достаточно маленьким для последовательной обработки. Здесь мы предполагаем, что порядок обработки подзадач не важен; разные (разветвлённые) задачи могут дополнительно разделять и обрабатывать элементы параллельно в неопределённом порядке. В этом примере используетсяCountedCompleter; аналогичные применения относятся к другим конструкциям параллельных задач.static <T> void parEach(TaggedArray<T> a, Consumer<T> action) { Spliterator<T> s = a.spliterator(); long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8); new ParEach(null, s, action, targetBatchSize).invoke(); } static class ParEach<T> extends CountedCompleter<Void> { final Spliterator<T> spliterator; final Consumer<T> action; final long targetBatchSize; ParEach(ParEach<T> parent, Spliterator<T> spliterator, Consumer<T> action, long targetBatchSize) { super(parent); this.spliterator = spliterator; this.action = action; this.targetBatchSize = targetBatchSize; } public void compute() { Spliterator<T> sub; while (spliterator.estimateSize() > targetBatchSize && (sub = spliterator.trySplit()) != null) { addToPendingCount(1); new ParEach<>(this, sub, action, targetBatchSize).fork(); } spliterator.forEachRemaining(action); propagateCompletion(); } } - Источник не может подвергаться структурным изменениям.
- Примечание по реализации:
- Если булева системная переменная
org.openjdk.java.util.stream.tripwireустановлена в значениеtrue, то будут выводиться предупреждения о диагностике, если происходит упаковывание примитивных значений при работе со специализациями примитивных подтипов. - С:
- 1.8
- См. также:
Collection
Вложенные классы
| Модификатор и тип | Интерфейс | Описание |
|---|---|---|
static interface | Spliterator.OfDouble | Специализированный Spliterator для значений |
static interface | Spliterator.OfInt | Специализированный Spliterator для значений |
static interface | Spliterator.OfLong | Специализированный Spliterator для значений |
static interface | Spliterator.OfPrimitive<T,T_CONS,T_SPLITR extends Spliterator.OfPrimitive<T,T_CONS,T_SPLITR>> | Специализированный Spliterator для примитивных значений. |
Поля
| Модификатор и тип | Поле | Описание |
|---|---|---|
static int | CONCURRENT | Значение характеристики, указывающее, что источник элементов можно безопасно одновременно изменять (добавлять, заменять и/или удалять) несколькими потоками без внешней синхронизации. |
static int | DISTINCT | Значение характеристики, указывающее, что для каждой пары встреченных элементов |
static int | IMMUTABLE | Значение характеристики, указывающее, что источник элементов не может быть структурно изменен; то есть элементы не могут быть добавлены, заменены или удалены, поэтому такие изменения не могут произойти во время обхода. |
static int | NONNULL | Значение характеристики, указывающее, что источник гарантирует, что встреченные элементы не будут |
static int | ORDERED | Значение характеристики, указывающее, что порядок встреч элементов определён. |
static int | SIZED | Значение характеристики, указывающее, что значение, возвращаемое из |
static int | SORTED | Значение характеристики, указывающее, что порядок встреч следует определённому порядку сортировки. |
static int | SUBSIZED | Значение характеристики, указывающее, что все Spliterator'ы, полученные из |
Методы
| Модификатор и тип | Метод | Описание |
|---|---|---|
int | characteristics() | Возвращает набор характеристик этого Spliterator'а и его элементов. |
long | estimateSize() | Возвращает оценку количества элементов, которые были бы встречены при обходе |
default void | forEachRemaining(Consumer<? super T> action) | Выполняет заданное действие для каждого оставшегося элемента последовательно в текущем потоке, пока все элементы не будут обработаны или действие не выбросит исключение. |
default Comparator<? super T> | getComparator() | Если источник этого Spliterator'а |
default long | getExactSizeIfKnown() | Удобный метод, возвращающий |
default boolean | hasCharacteristics(int characteristics) | Возвращает |
boolean | tryAdvance(Consumer<? super T> action) | Если существует оставшийся элемент, выполняет заданное действие над ним, возвращая |
Spliterator<T> | trySplit() | Если этот spliterator может быть разделен, возвращает Spliterator, охватывающий элементы, которые после возвращения из этого метода не будут охватываться этим Spliterator'ом. |
Поля
ORDERED
static final int ORDERED
Характерное значение, означающее, что порядок встречи элементов задан. В этом случае этот Spliterator гарантирует, что метод trySplit() разделяет строгий префикс элементов, что метод tryAdvance(java.util.function.Consumer<? super T>) переходит на один элемент в порядке префикса и что forEachRemaining(java.util.function.Consumer<? super T>) выполняет действия в порядке встречи.
У Collection есть порядок встречи, если соответствующий Collection.iterator() документирует порядок. В таком случае порядок встречи совпадает с документированным порядком. В противном случае у коллекции нет порядка встречи.
- Примечание API:
- Порядок встречи гарантированно является возрастающим порядком индекса для любого
List. Но порядок не гарантируется для хэш-базированных коллекций, таких какHashSet. Клиенты Spliterator, который сообщает оORDERED, должны сохранять ограничения порядка в некоммутативных параллельных вычислениях. - См. также:
- Значения постоянных полей
DISTINCT
static final int DISTINCT
Характерное значение, означающее, что для каждой пары встреченных элементов x, y, !x.equals(y). Это относится, например, к Spliterator, основанному на Set.
- См. также:
- Значения постоянных полей
SORTED
static final int SORTED
Характерное значение, означающее, что порядок встречи соответствует определенному порядку сортировки. Если это так, метод getComparator() возвращает связанный Comparator, или null если все элементы являются Comparable и отсортированы по своему естественному порядку.
Spliterator, который сообщает о SORTED, должен также сообщать о ORDERED.
- Примечание API:
- Spliterators для
Collectionклассов в JDK, которые реализуютNavigableSetилиSortedSetсообщают оSORTED. - См. также:
- Значения постоянных полей
SIZED
static final int SIZED
Характерное значение, означающее, что возвращаемое значение из estimateSize() перед обходом или разделением представляет конечный размер, который, при отсутствии структурных изменений источника, представляет точный подсчет количества элементов, которые встретились бы при полном обходе.
- Примечание API:
- Большинство Spliterator для коллекций, которые охватывают все элементы коллекции
Collection, сообщают об этом признаке. Под-Spliterators, такие как те дляHashSet, которые охватывают подмножество элементов и приближают свой указанный размер, не делают этого. - См. также:
- Значения постоянных полей
NONNULL
static final int NONNULL
Характерное значение, означающее, что источник гарантирует, что встреченные элементы не будут null. (Это относится, например, к большинству конкурирующих коллекций, очередей и словарей.)
- См. также:
- Значения постоянных полей
IMMUTABLE
static final int IMMUTABLE
Характерное значение, означающее, что источник элементов не может быть структурно изменен; то есть элементы не могут быть добавлены, заменены или удалены, поэтому такие изменения не могут произойти во время обхода. Spliterator, который не сообщает о IMMUTABLE или CONCURRENT, должен иметь документированную политику (например, бросать ConcurrentModificationException) относительно структурного вмешательства, обнаруженного во время обхода.
- См. также:
- Значения постоянных полей
CONCURRENT
static final int CONCURRENT
Характерное значение, означающее, что источник элементов может быть безопасно изменен одновременно (разрешая добавления, замены и/или удаления) несколькими потоками без внешней синхронизации. В этом случае Spliterator должен иметь документированную политику относительно влияния изменений во время обхода.
Главный Spliterator не должен сообщать как о CONCURRENT, так и о SIZED, так как конечный размер, если он известен, может измениться, если источник одновременно изменяется во время обхода. Такой Spliterator несогласован, и о вычислениях, использующих этот Spliterator, нельзя гарантировать ничего.
Главный Spliterator не должен сообщать как о CONCURRENT, так и о IMMUTABLE, так как они взаимоисключают друг друга. Такой Spliterator несогласован, и о вычислениях, использующих этот Spliterator, нельзя гарантировать ничего. Под-Spliterators могут сообщать о IMMUTABLE, если добавления или удаления источника не отражаются при обходе.
- Примечание API:
- Большинство конкурирующих коллекций поддерживают политику согласованности, гарантирующую точность по отношению к элементам, присутствующим в момент построения Spliterator, но, возможно, не отражающих последующие добавления или удаления.
- См. также:
- Значения постоянных полей
SUBSIZED
static final int SUBSIZED
Характерное значение, означающее, что все Spliterators, полученные в результате trySplit(), будут и SIZED, и SUBSIZED. (Это означает, что все дочерние Spliterators, прямые или косвенные, будут SIZED.)
Spliterator, который не сообщает о SIZED как требуется SUBSIZED, несогласован, и о вычислениях, использующих этот Spliterator, нельзя гарантировать ничего.
- Примечание API:
- Некоторые Spliterators, такие как основной Spliterator для сбалансированного бинарного дерева, будут сообщать о
SIZED, но не оSUBSIZED, так как обычно известен размер всего дерева, но не точные размеры поддеревьев. - См. также:
- Значения постоянных полей
Методы
tryAdvance
boolean tryAdvance(Consumer<? super T> action)
Если существует оставшийся элемент, выполняет заданное действие над ним, возвращая true; в противном случае возвращает false. Если этот Spliterator является ORDERED, действие выполняется над следующим элементом в порядке встречи. Исключение, выброшенное действием, передается вызывающему методу.
- Параметры:
-
action- Действие - Возвращает:
-
falseесли при входе в этот метод не существовало оставшихся элементов, в противном случаеtrue. - Исключения:
-
NullPointerException- если указанное действие равно null
forEachRemaining
default void forEachRemaining(Consumer<? super T> action)
Выполняет заданное действие для каждого оставшегося элемента последовательно в текущей нити, пока все элементы не будут обработаны или действие не выбросит исключение. Если этот Spliterator является ORDERED, действия выполняются в порядке встречи. Исключение, выброшенное действием, передается вызывающему методу.
- Требования к реализации:
- Базовая реализация многократно вызывает
tryAdvance(java.util.function.Consumer<? super T>), пока не вернётfalse. Она должна переопределяться всякий раз, когда это возможно. - Параметры:
-
action- Действие - Исключения:
-
NullPointerException- если указанное действие равно null
trySplit
Spliterator<T> trySplit()
Если этот итератор может быть разбит, возвращает Spliterator, охватывающий элементы, которые после возврата из этого метода, не будут охватываться этим Spliterator.
Если этот Spliterator является ORDERED, возвращаемый Spliterator должен охватывать строгий префикс элементов.
Если этот Spliterator не охватывает бесконечное количество элементов, повторные вызовы trySplit() должны в конечном итоге вернуть null. При ненулевом возврате:
- значение, сообщённое для
estimateSize()до разделения, должно после разделения быть больше или равноestimateSize()для этого и возвращённого Spliterator; и - если этот Spliterator является
SUBSIZED, тоestimateSize()для этого Spliterator до разделения должны быть равны суммеestimateSize()для этого и возвращённого Spliterator после разделения.
Этот метод может вернуть null по любой причине, включая пустоту, невозможность разделения после начала обхода, ограничения структуры данных и соображения эффективности.
- Примечание API:
- Идеальный метод
trySplitэффективно (без обхода) делит свои элементы точно пополам, позволяя сбалансированное параллельное вычисление. Многие отклонения от этого идеала остаются высокоэффективными; например, только приблизительное разделение приблизительно сбалансированного дерева или для дерева, в котором узлы листьев могут содержать либо один, либо два элемента, не производя дальнейшего разделения этих узлов. Однако значительные отклонения в балансе и/или слишком неэффективные механизмыtrySplitобычно приводят к плохой параллельной производительности. - Возвращает:
- Spliterator, охватывающий часть элементов, или
nullесли этот итератор нельзя разделить
estimateSize
long estimateSize()
Возвращает оценку количества элементов, которые будут встречены при обходе forEachRemaining(java.util.function.Consumer<? super T>), или возвращает Long.MAX_VALUE, если бесконечно, неизвестно или слишком дорого вычисляется.
Если этот Spliterator является SIZED и ещё не был частично пройден или разделён, или этот Spliterator является SUBSIZED и ещё не был частично пройден, эта оценка должна быть точным подсчётом элементов, которые будут встречены при полном обходе. В противном случае эта оценка может быть произвольно неточной, но должна уменьшаться, как указано при вызовах trySplit().
- Примечание API:
- Даже неточная оценка часто полезна и недорога в вычислении. Например, под-итератор приблизительно сбалансированного бинарного дерева может возвращать значение, которое оценивает количество элементов наполовину от количества его родительского элемента; если корневой Spliterator не поддерживает точный счёт, он может оценить размер как степень двойки, соответствующую максимальной глубине.
- Возвращает:
- оценённый размер или
Long.MAX_VALUEпри бесконечном, неизвестном или слишком дорогом вычислении.
getExactSizeIfKnown
default long getExactSizeIfKnown()
Удобный метод, который возвращает estimateSize(), если этот Spliterator является SIZED, в противном случае -1.
- Требования к реализации:
- Базовая реализация возвращает результат
estimateSize()если Spliterator отчитывается о характеристикеSIZED, и-1в противном случае. - Возвращает:
- точный размер, если известен, в противном случае
-1.
characteristics
int characteristics()
Возвращает набор характеристик этого Spliterator и его элементов. Результат представлен как ORed значения из ORDERED, DISTINCT, SORTED, SIZED, NONNULL, IMMUTABLE, CONCURRENT, SUBSIZED. Повторные вызовы characteristics() для данного Spliterator до или между вызовами trySplit всегда должны возвращать один и тот же результат.
Если Spliterator сообщает о несогласованном наборе характеристик (либо при одном вызове, либо при нескольких вызовах), о любых вычислениях, использующих этот Spliterator, нельзя делать никаких гарантий.
- Примечание API:
- Характеристики данного Spliterator до разделения могут отличаться от характеристик после разделения. Для конкретных примеров см. значения характеристик
SIZED,SUBSIZEDиCONCURRENT. - Возвращает:
- представление характеристик
hasCharacteristics
default boolean hasCharacteristics(int characteristics)
Возвращает true если характеристики этого Spliterator, указанные в characteristics(), содержат все заданные характеристики.
- Требования к реализации:
- Базовая реализация возвращает true, если соответствующие биты заданных характеристик установлены.
- Параметры:
-
characteristics- характеристики для проверки - Возвращает:
-
trueесли все указанные характеристики присутствуют, в противном случаеfalse
getComparator
default Comparator<? super T> getComparator()
Если источник этого Spliterator SORTED по Comparator, возвращает этот Comparator. Если источник является SORTED в естественном порядке, возвращает null. В противном случае, если источник не SORTED, выбрасывает IllegalStateException.
- Требования к реализации:
- Базовая реализация всегда выбрасывает
IllegalStateException. - Возвращает:
- Comparator или
nullесли элементы отсортированы в естественном порядке. - Исключения:
-
IllegalStateException- если Spliterator не сообщает о характеристикеSORTED.
© 1993, 2020, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Spliterator.html