He leído algunas de las preguntas de cómo crear un finitos Stream
( Finite genera corriente en Java - cómo crear uno? , ¿Cómo corrientes parada? ).
Las respuestas sugeridas para implementar una Spliterator
. El Spliterator
sería implementar la lógica de cómo y qué elemento para proporcionar como siguiente ( tryAdvance
). Pero hay otros dos métodos no predeterminados trySplit
y estimateSize()
los que me tendrían que poner en práctica.
El JavaDoc de Spliterator
dice:
Un objeto para atravesar y los elementos de una fuente de partición. La fuente de los elementos de cubierta por una
Spliterator
podría ser, por ejemplo, una matriz, unaCollection
, un canal IO, o una función de generador. ... ElSpliterator
API fue diseñado para apoyar el recorrido paralelo eficiente, además de recorrido secuencial, mediante el apoyo a la descomposición, así como iteración de un solo elemento. ...
Por otro lado pude implementar la lógica de la manera de avanzar al siguiente elemento en torno a una Stream.Builder
y bypass una Spliterator
. En cada avance que yo llamaría accept
o add
y al final build
. Así que parece bastante simple.
¿Qué dice la JavaDoc?
Un constructor mutable para una
Stream
. Esto permite la creación de unaStream
mediante la generación de elementos de forma individual y añadiéndolos a laBuilder
(sin la sobrecarga de copiar que proviene del uso de unArrayList
como un búfer temporal.)
Usando StreamSupport.stream
Puedo utilizar una Spliterator
para obtener una Stream
. Y también un Builder
proporcione será una Stream
.
Cuando debería / podría utilizar una Stream.Builder
?
Sólo si un Spliterator
no habría más eficiente (por ejemplo, porque la fuente no puede ser dividida y su tamaño no puede ser estimado)?
Tenga en cuenta que se puede extender Spliterators.AbstractSpliterator
. A continuación, sólo hay tryAdvance
que poner en práctica.
Por lo que la complejidad de la implementación de un Spliterator
no es más alta.
La diferencia fundamental es que un Spliterator
's tryAdvance
método sólo se invoca cuando se necesita un nuevo elemento. Por el contrario, el Stream.Builder
tiene un almacenamiento que se llenará con todos los elementos de flujo, antes de poder adquirir un arroyo.
Por lo que una Spliterator
es la primera opción para todo tipo de evaluación perezosa, así como cuando se tiene un almacenamiento existente quiere realizar el desplazamiento, para evitar la copia de los datos.
El constructor es la primera opción cuando la creación de los elementos no es uniforme, por lo que no se puede expresar la creación de un elemento bajo demanda. Pensar en situaciones en las que usaría otra manera Stream.of(…)
, pero resulta ser que inflexibles.
Por ejemplo, que tiene Stream.of(a, b, c, d, e)
, pero ahora resulta que, c
y d
son opcionales. Así que la solución es
Stream.Builder<MyType> builder = Stream.builder();
builder.add(a).add(b);
if(someCondition) builder.add(c).add(d);
builder.add(e).build()
/* stream operations */
Otros casos de uso son esta respuesta , donde una Consumer
se necesitaba para consultar un spliterator existente y empuje la parte posterior a un valor Stream
después, o esta respuesta , en una estructura sin acceso aleatorio (una jerarquía de clases) debe ser transmitido en el orden opuesto.