Je me demande pourquoi l' Iterable
interface ne fournit pas les méthodes stream()
et parallelStream()
. Considérez la classe suivante:
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();
}
}
Il s'agit d'une implémentation d'une main car vous pouvez avoir des cartes en main tout en jouant à un jeu de cartes à collectionner.
Essentiellement, il enveloppe un List<Card>
, assure une capacité maximale et offre d'autres fonctionnalités utiles. C'est mieux que de l'implémenter directement en tant que List<Card>
.
Maintenant, pour plus de commodité, j'ai pensé que ce serait bien de l'implémenter Iterable<Card>
, de sorte que vous pouvez utiliser des boucles for améliorées si vous voulez faire une boucle dessus. (Ma Hand
classe fournit également une get(int index)
méthode, d'où la Iterable<Card>
justification à mon avis.)
L' Iterable
interface fournit les éléments suivants (javadoc omis):
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);
}
}
Maintenant, pouvez-vous obtenir un flux avec:
Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);
Donc, sur la vraie question:
- Pourquoi ne
Iterable<T>
fournit pas de méthodes par défaut qui implémententstream()
etparallelStream()
, je ne vois rien qui rendrait cela impossible ou indésirable?
Une question connexe que j'ai trouvée est la suivante: pourquoi Stream <T> n'implémente-t-il pas Iterable <T>?
Ce qui est assez curieusement suggérant de le faire un peu l'inverse.
la source
break;
une itération? (D'accord, celaStream.findFirst()
pourrait être une solution, mais cela pourrait ne pas répondre à tous les besoins ...)Réponses:
Ce n'était pas une omission; il y a eu une discussion détaillée sur la liste EG en juin 2013.
La discussion définitive du Groupe d'experts est enracinée dans ce fil .
S'il est apparu "évident" (même au Groupe d'experts, au départ) que
stream()
semblait logiqueIterable
, le fait que ceIterable
soit si général devenait un problème, car la signature évidente:n'était pas toujours ce que vous vouliez. Certaines choses qui
Iterable<Integer>
auraient préféré que leur méthode stream renvoie unIntStream
, par exemple. Mais mettre lastream()
méthode aussi haut dans la hiérarchie rendrait cela impossible. Au lieu de cela, nous avons rendu très facile la créationStream
d'unIterable
, en fournissant unespliterator()
méthode. L'implémentation destream()
inCollection
est juste:N'importe quel client peut obtenir le flux de son choix
Iterable
avec:En fin de compte, nous avons conclu que l'ajout
stream()
deIterable
serait une erreur.la source
Iterable<Integer>
(je pense que vous parlez?) Voudrait retourner unIntStream
. L'itérable ne serait-il pas alors plutôt unPrimitiveIterator.OfInt
? Ou voulez-vous dire peut-être un autre cas d'utilisation?Stream.of(Iterable)
, ce qui rendrait au moins la méthode raisonnablement détectable en lisant la documentation de l'API - comme quelqu'un qui n'a jamais vraiment travaillé avec les composants internes de Streams, je ne l'aurais jamais fait même regardé àStreamSupport
, qui est décrit dans la documentation en fournissant des « opérations de bas niveau » qui sont « la plupart du temps pour les écrivains bibliothèque ».J'ai fait une enquête dans plusieurs des listes de diffusion du projet lambda et je pense avoir trouvé quelques discussions intéressantes.
Je n'ai jusqu'à présent pas trouvé d'explication satisfaisante. Après avoir lu tout cela, j'ai conclu que c'était juste une omission. Mais vous pouvez voir ici qu'il a été discuté plusieurs fois au cours des années lors de la conception de l'API.
Experts en spécifications Lambda Libs
J'ai trouvé une discussion à ce sujet dans la liste de diffusion Lambda Libs Spec Experts :
Sous Iterable / Iterator.stream (), Sam Pullara a déclaré:
Et puis Brian Goetz a répondu :
Et ensuite
Discussions précédentes dans la liste de diffusion Lambda
Ce n'est peut-être pas la réponse que vous recherchez, mais dans la liste de diffusion Project Lambda cela a été brièvement discuté. Cela peut peut-être favoriser une discussion plus large sur le sujet.
Pour reprendre les mots de Brian Goetz sous Streams from Iterable :
Contradiction?
Cependant, il semble que la discussion soit basée sur les changements que le Groupe d'experts a apportés à la conception initiale des Streams qui était initialement basée sur des itérateurs.
Même ainsi, il est intéressant de noter que dans une interface comme Collection, la méthode stream est définie comme:
Ce qui pourrait être exactement le même code utilisé dans l'interface Iterable.
C'est pourquoi j'ai dit que cette réponse n'est probablement pas satisfaisante, mais toujours intéressante pour la discussion.
Preuve de refactorisation
Poursuivant l'analyse dans la liste de diffusion, il semble que la méthode splitIterator était à l'origine dans l'interface Collection, et à un moment donné en 2013, ils l'ont déplacée vers Iterable.
Tirez splitIterator de Collection à Iterable .
Conclusion / Théories?
Ensuite, il est probable que l'absence de la méthode dans Iterable ne soit qu'une omission, car il semble qu'ils auraient également dû déplacer la méthode de flux lorsqu'ils ont déplacé le splitIterator de Collection à Iterable.
S'il y a d'autres raisons, celles-ci ne sont pas évidentes. Quelqu'un d'autre a d'autres théories?
la source
spliterator()
laIterable
, tous les problèmes sont fixés, et vous pouvez trivialement mettre en œuvrestream()
etparallelStream()
..Si vous connaissez la taille que vous pourriez utiliser et
java.util.Collection
qui fournit lastream()
méthode:Puis:
J'ai rencontré le même problème et j'ai été surpris que mon
Iterable
implémentation puisse être très facilement étendue à uneAbstractCollection
implémentation en ajoutant simplement lesize()
méthode (heureusement, j'avais la taille de la collection :-)Vous devez également envisager de remplacer
Spliterator<E> spliterator()
.la source