Eu fiz uma investigação em várias listas de discussão lambda do projeto e acho que encontrei algumas discussões interessantes.
Até agora não encontrei uma explicação satisfatória. Depois de ler tudo isso, concluí que era apenas uma omissão. Mas você pode ver aqui que foi discutido várias vezes ao longo dos anos durante o design da API.
Especialistas em especificações da Lambda Libs
Encontrei uma discussão sobre isso na lista de correspondência Lambda Libs Spec Experts :
Em Iterable / Iterator.stream (), Sam Pullara disse:
Eu estava trabalhando com Brian para ver como a funcionalidade limite / substream [1] poderia ser implementada e ele sugeriu que a conversão para o Iterator era o caminho certo. Eu tinha pensado nessa solução, mas não encontrei nenhuma maneira óbvia de pegar um iterador e transformá-lo em um fluxo. Acontece que ele está lá, basta converter o iterador em um spliterator e depois converter o spliterator em um fluxo. Portanto, isso me leva a revisitar se devemos pendurar esses itens diretamente no Iterable / Iterator ou em ambos.
Minha sugestão é pelo menos tê-lo no Iterator para que você possa se mover de maneira limpa entre os dois mundos e também seria fácil de descobrir, em vez de precisar fazer:
Streams.stream (Spliterators.spliteratorUnknownSize (iterador, Spliterator.ORDERED))
E então Brian Goetz respondeu :
Acho que o argumento de Sam foi que existem muitas classes de bibliotecas que oferecem um iterador, mas não permitem que você escreva seu próprio spliterator. Então, tudo o que você pode fazer é chamar o fluxo (spliteratorUnknownSize (iterador)). Sam está sugerindo que definamos Iterator.stream () para fazer isso por você.
Eu gostaria de manter os métodos stream () e spliterator () como sendo para escritores de bibliotecas / usuários avançados.
E depois
"Dado que escrever um Spliterator é mais fácil do que escrever um Iterator, eu preferiria apenas escrever um Spliterator em vez de um Iterator (o Iterator tem mais de 90 anos :)"
Você está perdendo o ponto, no entanto. Existem milhões de classes por aí que já lhe entregam um iterador. E muitos deles não estão prontos para spliterator.
Discussões anteriores na lista de distribuição do Lambda
Essa pode não ser a resposta que você está procurando, mas na lista de discussão do Project Lambda isso foi discutido brevemente. Talvez isso ajude a promover uma discussão mais ampla sobre o assunto.
Nas palavras de Brian Goetz, sob Streams from Iterable :
Recuando ...
Existem várias maneiras de criar um fluxo. Quanto mais informações você tiver sobre como descrever os elementos, mais funcionalidade e desempenho a biblioteca de fluxos poderá fornecer. Em ordem do mínimo para a maioria das informações, elas são:
Iterador
Iterador + tamanho
Spliterator
Spliterator que sabe seu tamanho
Spliterator que sabe seu tamanho e ainda sabe que todas as subdivisões sabem seu tamanho.
(Alguns podem se surpreender ao descobrir que podemos extrair paralelismo mesmo de um iterador burro nos casos em que Q (trabalho por elemento) não é trivial.)
Se o Iterable tivesse um método stream (), ele apenas envolveria um Iterator com um Spliterator, sem informações de tamanho. Mas, a maioria das coisas que são Iterable fazer tem informações de tamanho. O que significa que estamos fornecendo fluxos deficientes. Isso não é tão bom.
Uma desvantagem da prática de API descrita por Stephen aqui, de aceitar o Iterable em vez de Collection, é que você está forçando as coisas através de um "pequeno canal" e, portanto, descartando informações de tamanho quando isso pode ser útil. Tudo bem se tudo o que você estiver fazendo for forCada vez, mas se você quiser fazer mais, será melhor preservar todas as informações que desejar.
O padrão fornecido pelo Iterable seria realmente ruim - descartaria o tamanho mesmo que a grande maioria dos Iterables conheça essas informações.
Contradição?
Embora, parece que a discussão se baseia nas mudanças que o Grupo de Especialistas fez no design inicial do Streams, que foi inicialmente baseado em iteradores.
Mesmo assim, é interessante notar que em uma interface como Collection, o método stream é definido como:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Qual poderia ser exatamente o mesmo código que está sendo usado na interface Iterable.
Então, foi por isso que eu disse que essa resposta provavelmente não é satisfatória, mas ainda é interessante para a discussão.
Evidência de refatoração
Continuando com a análise na lista de correspondência, parece que o método splitIterator estava originalmente na interface Collection e, em algum momento de 2013, eles o moveram para Iterable.
Puxe splitIterator para cima de Collection para Iterable .
Conclusão / Teorias?
Então, é provável que a falta do método no Iterable seja apenas uma omissão, pois parece que eles deveriam ter movido o método stream também quando moveram o splitIterator de Collection para Iterable.
Se houver outras razões, essas não são evidentes. Alguém mais tem outras teorias?