Eu estou querendo saber por que a Iterable
interface não fornece os métodos stream()
e parallelStream()
. Considere a seguinte classe:
public class Hand implements Iterable<Card> {
private final List<Card> list = new ArrayList<>();
private final int capacity;
//...
@Override
public Iterator<Card> iterator() {
return list.iterator();
}
}
É uma implementação de uma Mão, pois você pode ter cartas na sua mão enquanto joga um Jogo de Cartas Colecionáveis.
Essencialmente, ele envolve a List<Card>
, garante uma capacidade máxima e oferece alguns outros recursos úteis. É melhor implementá-lo diretamente como um List<Card>
.
Agora, por conveniência, pensei que seria bom implementar Iterable<Card>
, de modo que você possa usar loops for-for aprimorados se desejar fazer um loop sobre ele. (Minha Hand
classe também fornece um get(int index)
método, portanto, isso Iterable<Card>
é justificado na minha opinião.)
A Iterable
interface fornece o seguinte (excluído o javadoc):
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
Agora você pode obter um fluxo com:
Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);
Então, para a verdadeira questão:
- Por que
Iterable<T>
não fornece métodos padrão que implementamstream()
eparallelStream()
não vejo nada que torne isso impossível ou indesejado?
Uma pergunta relacionada que encontrei é a seguinte: Por que o Stream <T> não implementa o Iterable <T>?
O que é curiosamente sugerido para fazê-lo de outra maneira.
fonte
break;
uma iteração? (Ok,Stream.findFirst()
pode ser uma solução, mas que pode não satisfazer todas as necessidades ...)Respostas:
Isso não foi uma omissão; houve discussão detalhada na lista de EG em junho de 2013.
A discussão definitiva do grupo de especialistas está enraizada neste tópico .
Embora parecesse "óbvio" (até mesmo para o grupo de especialistas) que
stream()
parecia fazer sentidoIterable
, o fato deIterable
ser tão geral se tornou um problema, devido à assinatura óbvia:nem sempre era o que você ia querer. Algumas coisas que
Iterable<Integer>
prefeririam que seu método stream retornasse umIntStream
, por exemplo. Mas colocar ostream()
método tão alto na hierarquia tornaria isso impossível. Então, em vez disso, facilitamos muito a criaçãoStream
de aIterable
, fornecendo umspliterator()
método. A implementação destream()
inCollection
é apenas:Qualquer cliente pode obter o fluxo que deseja de um
Iterable
com:No final, concluímos que adicionar
stream()
aIterable
seria um erro.fonte
Iterable<Integer>
(acho que você está falando?) Gostaria de retornar umIntStream
. O iterável então não seria umPrimitiveIterator.OfInt
? Ou você quer dizer outro caso de uso?Stream.of(Iterable)
, que pelo menos tornaria o método razoavelmente detectável ao ler a documentação da API - como alguém que nunca trabalhou realmente com os internos do Streams que eu nunca mesmo olhou emStreamSupport
, que é descrito na documentação como o fornecimento de "operações de baixo nível", que são "principalmente para escritores de biblioteca".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:
E então Brian Goetz respondeu :
E depois
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 :
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:
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?
fonte
spliterator()
doIterable
, então todas as questões não são fixos, e você pode trivialmente implementarstream()
eparallelStream()
..Se você souber o tamanho que pode usar,
java.util.Collection
que fornece ostream()
método:E depois:
Eu enfrentei o mesmo problema e fiquei surpreso que minha
Iterable
implementação pudesse ser facilmente estendida a umaAbstractCollection
implementação simplesmente adicionando osize()
método (felizmente eu tinha o tamanho da coleção :-)Você também deve considerar substituir
Spliterator<E> spliterator()
.fonte