Интерфейс 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>
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 должен, насколько это возможно, выбрасывать ConcurrentModificationException, если обнаружено структурное вмешательство. Такие сплитераторы называются fail-fast. Пакетный метод обхода (forEachRemaining()) Spliterator может оптимизировать обход и проверять наличие структурного вмешательства после обхода всех элементов, а не проверять каждый элемент и немедленно завершаться с ошибкой.
Сплитераторы могут предоставлять оценку количества оставшихся элементов с помощью метода estimateSize(). В идеальном случае, как отражено характеристикой SIZED, это значение точно соответствует количеству элементов, которые будут встречены при успешном обходе. Однако даже если точное значение неизвестно, его оценка может быть полезна для операций с источником, например для определения того, предпочтительнее ли продолжить разделение или последовательно обойти оставшиеся элементы.
Несмотря на очевидную полезность в параллельных алгоритмах, сплитераторы не должны быть потокобезопасными; вместо этого реализации параллельных алгоритмов с использованием сплитераторов должны обеспечивать, чтобы в каждый момент времени сплитератор использовался только одним потоком. Обычно этого легко добиться с помощью последовательной привязки к потоку, которая часто естественным образом возникает в типичных параллельных алгоритмах, работающих путем рекурсивного разбиения. Поток, вызывающий trySplit(), может передать возвращенный Spliterator другому потоку, который, в свою очередь, может обходить или дополнительно разделять этот Spliterator. Поведение разделения и обхода не определено, если с одним и тем же сплитератором одновременно работают два или более потоков. Если исходный поток передает сплитератор другому потоку для обработки, лучше сделать это до того, как будут потреблены какие-либо элементы с помощью tryAdvance(), поскольку некоторые гарантии (например, точность estimateSize() для сплитераторов SIZED) действуют только до начала обхода.
Для примитивных типов предусмотрены специализированные подтипы Spliterator: int, long и double. Реализации методов tryAdvance(java.util.function.Consumer) и forEachRemaining(java.util.function.Consumer) по умолчанию для подтипов упаковывают примитивные значения в экземпляры соответствующего класса-оболочки. Такая упаковка может свести на нет преимущества в производительности, полученные благодаря использованию специализаций для примитивов. Чтобы избежать упаковки, следует использовать соответствующие методы для примитивных типов. Например, вместо Spliterator.OfInt.tryAdvance(java.util.function.Consumer) и Spliterator.OfInt.forEachRemaining(java.util.function.Consumer) предпочтительно использовать Spliterator.OfPrimitive.tryAdvance(java.util.function.IntConsumer) и Spliterator.OfPrimitive.forEachRemaining(java.util.function.IntConsumer). Обход примитивных значений с помощью методов, основанных на упаковке, tryAdvance() и forEachRemaining(), не влияет на порядок, в котором встречаются значения, преобразованные в упакованные значения.
- Примечание API:
-
Сплитераторы, как и
Iteratorы, предназначены для обхода элементов источника. APISpliteratorразработан для поддержки эффективного параллельного обхода в дополнение к последовательному обходу: он поддерживает как разбиение, так и итерацию по отдельным элементам. Кроме того, протокол доступа к элементам через Spliterator разработан так, чтобы накладные расходы на каждый элемент были меньше, чем уIterator, и чтобы избежать неизбежной гонки, возникающей при использовании отдельных методов дляhasNext()иnext().Для изменяемых источников структурное вмешательство в источник (добавление, замена или удаление элементов) между моментом привязки Spliterator к источнику данных и завершением обхода может привести к произвольному и недетерминированному поведению. Например, такое вмешательство приведет к произвольным недетерминированным результатам при использовании платформы
java.util.stream.Структурное вмешательство в источник можно обрабатывать следующими способами (примерно в порядке убывания предпочтительности):
- Структурное вмешательство в источник невозможно.
Например, экземплярCopyOnWriteArrayListявляется неизменяемым источником. Созданный на основе этого источника Spliterator сообщает характеристикуIMMUTABLE. - Источник самостоятельно обрабатывает параллельные изменения.
Например, множество ключейConcurrentHashMapявляется параллельным источником. Созданный на основе этого источника Spliterator сообщает характеристикуCONCURRENT. - Изменяемый источник предоставляет Spliterator с отложенной привязкой и свойством fail-fast.
Отложенная привязка сокращает период, в течение которого вмешательство может повлиять на вычисления; свойство fail-fast по возможности обнаруживает структурное вмешательство после начала обхода и выбрасываетConcurrentModificationException. Например,ArrayListи многие другие непараллельные классыCollectionв JDK предоставляют Spliterator с отложенной привязкой и свойством fail-fast. - Изменяемый источник предоставляет Spliterator без отложенной привязки, но со свойством fail-fast.
Такой источник повышает вероятность выбрасыванияConcurrentModificationException, поскольку период потенциального вмешательства больше. - Изменяемый источник предоставляет Spliterator с отложенной привязкой, но без свойства fail-fast.
После начала обхода источник может вести себя произвольно и недетерминированно, поскольку вмешательство не обнаруживается. - Изменяемый источник предоставляет Spliterator без отложенной привязки и без свойства fail-fast.
Такой источник повышает риск произвольного недетерминированного поведения, поскольку необнаруженное вмешательство может произойти после создания.
Пример. Ниже приведен класс (не слишком полезный, кроме как для иллюстрации), который хранит массив: фактические данные размещаются в четных ячейках, а не связанные с ними метаданные — в нечетных. Его 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; } } }В качестве примера использования Spliterator параллельной вычислительной платформой, такой как пакет
java.util.stream, приведен один из способов реализации связанного с ним параллельного forEach, иллюстрирующий основной идиоматический способ применения: разделение на подзадачи продолжается до тех пор, пока предполагаемый объем работы не станет достаточно малым для последовательного выполнения. Здесь предполагается, что порядок обработки подзадач не имеет значения; разные задачи (созданные с помощью fork) могут дополнительно разделять и обрабатывать элементы параллельно в неопределенном порядке. В этом примере используется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
- См. также:
Краткое описание вложенных классов
| Модификатор и тип | Интерфейс | Описание |
|---|---|---|
static interface |
Spliterator.OfDouble |
Spliterator, специализированный для значений типа double. |
static interface |
Spliterator.OfInt |
Spliterator, специализированный для значений типа int. |
static interface |
Spliterator.OfLong |
Spliterator, специализированный для значений типа long. |
static interface |
Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, |
Spliterator, специализированный для примитивных значений. |
Краткое описание полей
| Модификатор и тип | Поле | Описание |
|---|---|---|
static final int |
CONCURRENT |
Значение характеристики, означающее, что источник элементов можно безопасно изменять параллельно (добавлять, заменять и/или удалять элементы) из нескольких потоков без внешней синхронизации. |
static final int |
DISTINCT |
Значение характеристики, означающее, что для каждой пары встреченных элементов x, y, !x.equals(y). |
static final int |
IMMUTABLE |
Значение характеристики, означающее, что структуру источника элементов нельзя изменять; то есть элементы нельзя добавлять, заменять или удалять, поэтому такие изменения не могут произойти во время обхода. |
static final int |
NONNULL |
Значение характеристики, означающее, что источник гарантирует отсутствие среди встреченных элементов значения null. |
static final int |
ORDERED |
Значение характеристики, означающее, что для элементов определен порядок обхода. |
static final int |
SIZED |
Значение характеристики, означающее, что значение, возвращаемое методом estimateSize() до начала обхода или разделения, представляет собой конечный размер, который при отсутствии структурного изменения источника точно соответствует количеству элементов, которые будут встречены при полном обходе. |
static final int |
SORTED |
Значение характеристики, означающее, что порядок обхода соответствует определенному порядку сортировки. |
static final int |
SUBSIZED |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
int |
characteristics() |
Возвращает набор характеристик этого Spliterator и его элементов. |
long |
estimateSize() |
Возвращает оценку количества элементов, которые будут встречены при обходе forEachRemaining(Consumer), или возвращает Long.MAX_VALUE, если количество бесконечно, неизвестно или его вычисление слишком затратно. |
default void |
forEachRemaining |
Последовательно, в текущем потоке, выполняет заданное действие для каждого оставшегося элемента, пока все элементы не будут обработаны или действие не вызовет исключение. |
default Comparator |
getComparator() |
|
default long |
getExactSizeIfKnown() |
Вспомогательный метод, возвращающий estimateSize(), если этот Spliterator имеет характеристику SIZED, и -1 в противном случае. |
default boolean |
hasCharacteristics |
Возвращает true, если среди characteristics() этого Spliterator есть все заданные характеристики. |
boolean |
tryAdvance |
Если имеется оставшийся элемент, выполняет над ним заданное действие и возвращает true; в противном случае возвращает false. |
Spliterator |
trySplit() |
Если этот сплитератор можно разделить, возвращает Spliterator, охватывающий элементы, которые после возврата из этого метода больше не будут охватываться данным Spliterator. |
Подробное описание полей
ORDERED
static final int ORDERED
trySplit() разделяет строгий префикс элементов, метод tryAdvance(Consumer) обрабатывает по одному элементу в порядке следования, а метод forEachRemaining(Consumer) выполняет действия в порядке следования. У 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:
- Spliterator-ы для
Collectionклассов JDK, реализующихNavigableSetилиSortedSet, сообщаютSORTED. - См. также:
SIZED
static final int SIZED
estimateSize() до обхода или разделения, представляет конечный размер и при отсутствии структурных изменений источника точно соответствует количеству элементов, которые будут обнаружены при полном обходе.- Примечание API:
- Большинство Spliterator-ов коллекций, охватывающих все элементы
Collection, сообщают эту характеристику. Spliterator-ы подмножеств, например дляHashSet, которые охватывают подмножество элементов и возвращают приблизительную оценку их количества, её не сообщают. - См. также:
NONNULL
static final int NONNULL
null. (Это относится, например, к большинству параллельных коллекций, очередей и отображений.)- См. также:
IMMUTABLE
static final int IMMUTABLE
IMMUTABLE или CONCURRENT, ожидается наличие документированной политики (например, выбрасывание ConcurrentModificationException) в отношении структурных изменений, обнаруженных во время обхода.- См. также:
CONCURRENT
static final int CONCURRENT
Spliterator верхнего уровня не должен сообщать одновременно CONCURRENT и SIZED, поскольку конечный размер, если он известен, может измениться, если источник будет изменён одновременно с обходом. Такой Spliterator противоречив, и никаких гарантий относительно вычислений с его использованием дать нельзя. Spliterator-ы подмножеств могут сообщать SIZED, если размер подмножества известен, а добавления или удаления в источнике не отражаются при обходе.
Spliterator верхнего уровня не должен сообщать одновременно CONCURRENT и IMMUTABLE, поскольку эти характеристики взаимоисключающие. Такой Spliterator противоречив, и никаких гарантий относительно вычислений с его использованием дать нельзя. Spliterator-ы подмножеств могут сообщать IMMUTABLE, если добавления или удаления в источнике не отражаются при обходе.
- Примечание API:
- Большинство параллельных коллекций придерживается политики согласованности, гарантирующей точность относительно элементов, присутствовавших в момент создания Spliterator, но не обязательно учитывающей последующие добавления или удаления.
- См. также:
SUBSIZED
static final int SUBSIZED
trySplit(), будут обладать характеристиками SIZED и SUBSIZED. (Это означает, что все дочерние Spliterator-ы, прямые или косвенные, будут SIZED.) Spliterator, который не сообщает SIZED, как того требует SUBSIZED, является противоречивым, и никаких гарантий относительно вычислений с его использованием дать нельзя.
- Примечание API:
- Некоторые Spliterator-ы, например 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)
ORDERED, действия выполняются в порядке следования. Исключения, выброшенные действием, передаются вызывающему коду. Последующее поведение сплитератора не определено, если действие выбрасывает исключение.
- Требования к реализации:
- Реализация по умолчанию многократно вызывает
tryAdvance(Consumer), пока метод не вернётfalse. По возможности этот метод следует переопределять. - Параметры:
-
action— действие - Выбрасывает:
-
NullPointerException— если заданное действие равно null
trySplit
Spliterator<T> trySplit()
Если этот Spliterator имеет характеристику ORDERED, возвращённый Spliterator должен охватывать строгий префикс элементов.
Если этот Spliterator не охватывает бесконечное число элементов, повторные вызовы trySplit() должны в конечном итоге вернуть null. При возврате ненулевого значения:
- значение, сообщённое для
estimateSize()до разделения, после разделения должно быть больше или равноestimateSize()для этого Spliterator и возвращённого Spliterator; и - если этот Spliterator имеет характеристику
SUBSIZED, то значениеestimateSize()для этого сплитератора до разделения должно быть равно сумме значенийestimateSize()для этого Spliterator и возвращённого Spliterator после разделения.
Этот метод может вернуть null по любой причине, в том числе из-за отсутствия элементов, невозможности разделения после начала обхода, ограничений структуры данных или соображений эффективности.
- Примечание API:
- Идеальный метод
trySplitэффективно (без обхода) делит элементы ровно пополам, обеспечивая сбалансированные параллельные вычисления. Многие отступления от этого идеала всё же дают высокую эффективность: например, приблизительное разделение приблизительно сбалансированного дерева или отказ от дальнейшего разделения узлов дерева, в которых листовые узлы могут содержать один или два элемента. Однако значительный дисбаланс и/или чрезмерно неэффективный механизмtrySplitобычно приводят к низкой производительности при параллельном выполнении. - Возвращает:
- Spliterator
Spliterator, охватывающий часть элементов, илиnull, если этот сплитератор нельзя разделить
estimateSize
long estimateSize()
forEachRemaining(Consumer), или возвращает Long.MAX_VALUE, если количество бесконечно, неизвестно или слишком затратно для вычисления. Если этот Spliterator имеет характеристику SIZED и ещё не был частично обойдён или разделён либо если этот Spliterator имеет характеристику SUBSIZED и ещё не был частично обойдён, эта оценка должна точно соответствовать количеству элементов, которые будут обнаружены при полном обходе. В противном случае оценка может быть произвольно неточной, но должна уменьшаться в соответствии с указанными правилами при вызовах trySplit().
- Примечание API:
- Даже неточная оценка часто полезна и вычисляется с небольшими затратами. Например, Spliterator подмножества для приблизительно сбалансированного бинарного дерева может вернуть значение, оценивающее количество элементов как половину количества элементов родительского узла; если корневой Spliterator не поддерживает точный подсчёт, он может оценить размер как степень двойки, соответствующую максимальной глубине дерева.
- Возвращает:
- оценку размера или
Long.MAX_VALUE, если количество бесконечно, неизвестно или слишком затратно для вычисления.
getExactSizeIfKnown
default long getExactSizeIfKnown()
estimateSize(), если этот Spliterator имеет характеристику SIZED; в противном случае возвращает -1.- Требования к реализации:
- Реализация по умолчанию возвращает результат
estimateSize(), если Spliterator сообщает характеристикуSIZED, и-1в противном случае. - Возвращает:
- точный размер, если он известен; в противном случае —
-1.
characteristics
int characteristics()
ORDERED, DISTINCT, SORTED, SIZED, NONNULL, IMMUTABLE, CONCURRENT, SUBSIZED. Повторные вызовы characteristics() для данного сплитератора до вызовов trySplit или между ними всегда должны возвращать один и тот же результат. Если Spliterator сообщает противоречивый набор характеристик (в результате одного вызова или нескольких вызовов), никаких гарантий относительно вычислений с его использованием дать нельзя.
- Примечание API:
- Характеристики данного сплитератора до разделения могут отличаться от характеристик после разделения. Конкретные примеры см. в описаниях значений характеристик
SIZED,SUBSIZEDиCONCURRENT. - Возвращает:
- представление характеристик
hasCharacteristics
default boolean hasCharacteristics(int characteristics)
true, если в characteristics() этого Spliterator присутствуют все заданные характеристики.- Требования к реализации:
- Реализация по умолчанию возвращает true, если установлены соответствующие биты заданных характеристик.
- Параметры:
-
characteristics— характеристики, наличие которых нужно проверить - Возвращает:
-
true, если присутствуют все указанные характеристики; в противном случае —false
getComparator
default Comparator<? super T> getComparator()
SORTED) с помощью Comparator, возвращает этот Comparator. Если источник SORTED в естественном порядке, возвращает null. В противном случае, если источник не имеет характеристики SORTED, выбрасывает IllegalStateException.- Требования к реализации:
- Реализация по умолчанию всегда выбрасывает
IllegalStateException. - Возвращает:
- Comparator или
null, если элементы отсортированы в естественном порядке. - Выбрасывает:
-
IllegalStateException— если сплитератор не сообщает характеристикуSORTED.
© 1993, 2025, 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/25/docs/api/java.base/java/util/Spliterator.html