Investigué en varias de las listas de correo lambda del proyecto y creo que encontré algunas discusiones interesantes.
No he encontrado una explicación satisfactoria hasta ahora. Después de leer todo esto, llegué a la conclusión de que era solo una omisión. Pero puede ver aquí que se discutió varias veces a lo largo de los años durante el diseño de la API.
Expertos en especificaciones de Lambda Libs
Encontré una discusión sobre esto en la lista de correo de expertos en especificaciones de Lambda Libs :
Bajo Iterable / Iterator.stream () Sam Pullara dijo:
Estaba trabajando con Brian para ver cómo se podría implementar la funcionalidad de límite / subtransmisión [1] y sugirió que la conversión a Iterator era la forma correcta de hacerlo. Había pensado en esa solución, pero no encontré ninguna forma obvia de tomar un iterador y convertirlo en una secuencia. Resulta que está allí, solo necesita convertir primero el iterador en un spliterator y luego convertir el spliterator en una secuencia. Esto me lleva a revisar si deberíamos tener estos colgando de Iterable / Iterator directamente o ambos.
Mi sugerencia es al menos tenerlo en Iterator para que pueda moverse limpiamente entre los dos mundos y también sería fácilmente detectable en lugar de tener que hacerlo:
Streams.stream (Spliterators.spliteratorUnknownSize (iterador, Spliterator.ORDERED))
Y luego Brian Goetz respondió :
Creo que el punto de Sam es que hay muchas clases de biblioteca que te dan un iterador pero no te dejan necesariamente escribir tu propio spliterator. Entonces, todo lo que puede hacer es llamar stream (spliteratorUnknownSize (iterator)). Sam sugiere que definamos Iterator.stream () para que lo haga por usted.
Me gustaría mantener los métodos stream () y spliterator () para escritores de bibliotecas / usuarios avanzados.
Y después
"Dado que escribir un Spliterator es más fácil que escribir un Iterator, preferiría escribir un Spliterator en lugar de un Iterator (Iterator es tan noventa :)".
Sin embargo, te estás perdiendo el punto. Hay millones de clases por ahí que ya te dan un iterador. Y muchos de ellos no están preparados para spliterator.
Discusiones anteriores en la lista de correo de Lambda
Puede que esta no sea la respuesta que está buscando, pero en la lista de correo del Proyecto Lambda esto se discutió brevemente. Quizás esto ayude a fomentar una discusión más amplia sobre el tema.
En palabras de Brian Goetz en Streams from Iterable :
Dar un paso atrás...
Hay muchas formas de crear un Stream. Cuanta más información tenga sobre cómo describir los elementos, más funcionalidad y rendimiento puede proporcionarle la biblioteca de secuencias. En orden de menor a mayor cantidad de información, son:
Iterador
Iterador + tamaño
Spliterator
Spliterator que conoce su tamaño
Spliterator que conoce su tamaño, y además sabe que todas las sub-divisiones conocen su tamaño.
(Algunos pueden sorprenderse al descubrir que podemos extraer paralelismo incluso de un iterador tonto en los casos en que Q (trabajo por elemento) no es trivial).
Si Iterable tuviera un método stream (), simplemente envolvería un iterador con un Spliterator, sin información de tamaño. Sin embargo, la mayoría de las cosas que son Iterable hacer tener información. Lo que significa que estamos sirviendo flujos deficientes. Eso no es tan bueno.
Una desventaja de la práctica API descrita aquí por Stephen, de aceptar Iterable en lugar de Collection, es que está forzando las cosas a través de una "pequeña tubería" y, por lo tanto, descarta la información de tamaño cuando puede ser útil. Está bien si todo lo que está haciendo es por Cada uno, pero si desea hacer más, es mejor si puede conservar toda la información que desea.
El valor predeterminado proporcionado por Iterable sería realmente malo: descartaría el tamaño a pesar de que la gran mayoría de los Iterables conocen esa información.
¿Contradicción?
Sin embargo, parece que la discusión se basa en los cambios que el Grupo de Expertos realizó en el diseño inicial de Streams, que inicialmente se basó en iteradores.
Aun así, es interesante notar que en una interfaz como Collection, el método de flujo se define como:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Que podría ser exactamente el mismo código que se utiliza en la interfaz Iterable.
Entonces, es por eso que dije que esta respuesta probablemente no sea satisfactoria, pero aún así es interesante para la discusión.
Evidencia de refactorización
Continuando con el análisis en la lista de correo, parece que el método splitIterator estaba originalmente en la interfaz de la Colección, y en algún momento en 2013 lo movieron a Iterable.
Tire splitIterator hacia arriba de la colección a Iterable .
Conclusión / Teorías?
Entonces lo más probable es que la falta del método en Iterable sea solo una omisión, ya que parece que también deberían haber movido el método de flujo cuando movieron el SplitIterator de Collection a Iterable.
Si hay otras razones, esas no son evidentes. ¿Alguien más tiene otras teorías?