Я прочитал несколько вопросов, как создать конечный Stream (
Конечный сгенерированный поток в Java - как его создать?, Как останавливаются потоки?).
В ответах предлагалось реализовать Spliterator. Spliterator будет реализовывать логику, как и какой элемент предоставить следующим (tryAdvance). Но есть два других нестандартных метода trySplit и estimateSize(), которые мне придется реализовать.
В JavaDoc Spliterator говорится:
An object for traversing and partitioning elements of a source. The source of elements covered by a
Spliteratorcould be, for example, an array, aCollection, an IO channel, or a generator function. ... TheSpliteratorAPI was designed to support efficient parallel traversal in addition to sequential traversal, by supporting decomposition as well as single-element iteration. ...
С другой стороны, я мог бы реализовать логику перехода к следующему элементу вокруг Stream.Builder и обхода Spliterator. При каждом продвижении я звонил accept или add и в конце build. Так что это выглядит довольно просто.
Что говорит JavaDoc?
A mutable builder for a
Stream. This allows the creation of aStreamby generating elements individually and adding them to theBuilder(without the copying overhead that comes from using anArrayListas a temporary buffer.)
Используя StreamSupport.stream, я могу использовать Spliterator для получения Stream. А также Builder предоставит Stream.
Когда следует / можно использовать Stream.Builder?
Только если Spliterator не будет более эффективным (например, из-за того, что источник не может быть разбит на разделы и его размер не может быть оценен)?
Я просто хочу добавить, что, хотя я написал несколько сплитераторов самостоятельно, это никогда не было забавной историей, возможно, для Хольгера это козырёк; но если вам действительно нужны дополнительные функции, Spliterator - это то, что вам нужно.




On the other hand I could implement the logic how to advance to the next element around a Stream.Builder and bypass a Spliterator. On every advance I would call
acceptoraddand at the endbuild. So it looks quite simple.
Да и нет. Это просто является, но я не думаю, что вы понимаете модель использования:
A stream builder has a lifecycle, which starts in a building phase, during which elements can be added, and then transitions to a built phase, after which elements may not be added. The built phase begins when the
build()method is called, which creates an orderedStreamwhose elements are the elements that were added to the stream builder, in the order they were added.
(Javadocs)
В частности, нет, вы не должны вызывать метод Stream.Builder или acceptadd при любом продвижении потока. Вам необходимо заранее предоставить все объекты для потока в. Затем вы build(), чтобы получить поток, который предоставит все объекты, которые вы добавили ранее. Это аналогично добавлению всех объектов в List и последующему вызову метода List этого stream().
Если это служит вашим целям и вы действительно можете делать это эффективно, тогда отлично! Но если вам нужно генерировать элементы по мере необходимости, с лимитом или без него, Stream.Builder вам не поможет. Spliterator может.
Stream.Builder.accept, а не на Stream. Я имел в виду, что таким образом я могу добавить каждый элемент в Stream.Builder, аналогично тому, как Spliterator.tryAdvance предоставляет каждый элемент.
@LuCio tryAdvanceпотенциально предоставляет каждый элемент, но может не вызываться для каждого элемента, поскольку потоку они могут не понадобиться. Но вы должны вызвать Stream.Builder.accept или add для каждого элемента, прежде чем вы сможете создать поток, не зная, все ли они нужны. Вызов метода для каждого элемента или реализация метода, потенциально обеспечивающего каждый элемент, представляют собой принципиально разные структуры кода. Обычно это естественный выбор.
@Holger Да. Это важное различие, которое я только что прочитал из вашего ответа.
@LuCio, вы написали: «Каждый раз я называл accept или add, а в конце - build». И да, конечно, вы можете создать поток, используя Stream.Builder.advance и, в конечном итоге, Stream.Builder.build. Вопрос в сроках. Как я уже сказал, если вы можете передать все элементы в Stream.Builder заранее, до того, как начнете обрабатывать поток, то это нормально. Но вы не можете вызывать accept или add одновременно с продвижением по потоку. В любом случае, если вы хотели сказать не это, тогда хорошо.
@JohnBollinger Thx за разъяснения.
Обратите внимание, что вы можете расширить Spliterators.AbstractSpliterator. Затем остается реализовать только tryAdvance.
Так что сложность реализации Spliterator не выше.
Принципиальное отличие состоит в том, что метод SpliteratortryAdvance вызывается только тогда, когда требуется новый элемент. Напротив, 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, или этот ответ, где структура без произвольного доступа (иерархия классов) должна передаваться в обратном порядке.
Я думаю, что ленивое оценивание - это очень важный и отличительный момент. Пример для Stream.Builder, где c и d являются необязательными, (если я вас правильно понял) похож на этот вопрос. Я собирался использовать Stream.Builder в качестве решения, но не был уверен, подходит ли оно.
Я тупой, я новичок в java, и я вижу функции Stream.builder () и build (), пожалуйста, помогите мне понять !!!
@nitinsridar, в чем именно заключается ваш вопрос?
Что такое буйдер? Я вижу в elasticsearch, apache kafka, но я не понимаю, что на самом деле делает строитель? @Holger
@nitinsridar метод Stream.builder(), который возвращает экземпляр класс Stream.Builder.
Все сводится к тому, чтобы толкать или тянуть.