Spliterator vs Stream.Builder - PullRequest
       14

Spliterator vs Stream.Builder

0 голосов
/ 14 сентября 2018

Я прочитал несколько вопросов, как создать конечное Stream ( Конечный сгенерированный поток в Java - как его создать? , Как остановить потоки? ).

Ответы, предложенные для реализации Spliterator. Spliterator будет реализовывать логику, как и какой элемент предоставить как следующий (tryAdvance). Но есть два других нестандартных метода trySplit и estimateSize(), которые я должен был бы реализовать.

JavaDoc Spliterator говорит:

Объект для обхода и разбиения элементов источника. Источником элементов, охватываемых Spliterator, может быть, например, массив, Collection, канал ввода-вывода или функция генератора. ... API Spliterator был разработан для поддержки эффективной параллельности обход в дополнение к последовательному обходу, поддерживая декомпозиция, а также одноэлементная итерация. ...

С другой стороны, я мог бы реализовать логику, как перейти к следующему элементу вокруг Stream.Builder и обойти Spliterator. На каждый аванс я бы звонил accept или add и в конце build. Так что это выглядит довольно просто.

Что говорит JavaDoc?

Изменчивый строитель для Stream. Это позволяет создавать Stream генерируя элементы по отдельности и добавляя их в Builder (без затрат на копирование из-за использования ArrayList в качестве временный буфер.)

Используя StreamSupport.stream Я могу использовать Spliterator для получения Stream. А также Builder обеспечит Stream.

Когда я должен / могу использовать Stream.Builder?
Только если Spliterator не будет более эффективным (например, потому что источник не может быть разбит на части и его размер не может быть оценен)?

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Обратите внимание, что вы можете продлить Spliterators.AbstractSpliterator.Тогда есть только tryAdvance для реализации.

Таким образом, сложность реализации Spliterator не выше.

Принципиальное отличие состоит в том, что Spliterator '* tryAdvanceМетод вызывается только тогда, когда необходим новый элемент.Напротив, Stream.Builder имеет хранилище , которое будет заполнено всеми элементами потока, прежде чем вы сможете получить поток.

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

Конструктор является первым выбором, когда создание элементов неоднородно, так что вы можетене выражают создание элемента по запросу.Подумайте о ситуациях, в которых вы в противном случае использовали бы Stream.of(…), но это оказывается негибким.

Например, у вас есть Stream.of(a, b, c, d, e), но теперь оказывается, что c и d являются необязательными.Таким образом, решение -

Stream.Builder<MyType> builder = Stream.builder();
builder.add(a).add(b);
if(someCondition) builder.add(c).add(d);
builder.add(e).build()
   /* stream operations */

Другими вариантами использования являются этот ответ , где Consumer был необходим для запроса существующего сплитератора и впоследствии возвращает значение обратно к Stream,или этот ответ , где структура без произвольного доступа (иерархия классов) должна передаваться в обратном порядке.

0 голосов
/ 14 сентября 2018

С другой стороны, я мог бы реализовать логику, как перейти к следующему элементу вокруг Stream.Builder и обойти Spliterator. На каждый аванс я бы звонил accept или add, а в конце build. Так что это выглядит довольно просто.

Да и нет. Это просто , но я не думаю, что вы понимаете модель использования:

Построитель потока имеет жизненный цикл, который начинается на этапе построения, в течение которого элементы могут быть добавлены, а затем переходит к этапу построения, после которого элементы не могут быть добавлены. Этап построения начинается, когда вызывается метод build(), который создает упорядоченный Stream, элементами которого являются элементы, которые были добавлены в построитель потока, в порядке их добавления.

( Javadocs )

В частности, нет, вы не будете вызывать Stream.Builder accept или add метод при любом продвижении потока. Вам необходимо предоставить все объекты для потока в заранее. Затем вы build() получите поток, который предоставит все ранее добавленные вами объекты. Это аналогично добавлению всех объектов в List и последующему вызову метода List stream().

Если это служит вашим целям, и вы действительно можете сделать это эффективно, тогда отлично! Но если вам нужно генерировать элементы по мере необходимости, с лимитом или без него, Stream.Builder вам не поможет. Spliterator банка.

...