Me pregunto por qué la Iterable
interfaz no proporciona los métodos stream()
y parallelStream()
. Considere la siguiente clase:
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();
}
}
Es una implementación de una Mano, ya que puedes tener cartas en tu mano mientras juegas un Juego de Cartas Coleccionables.
Esencialmente, envuelve a List<Card>
, asegura una capacidad máxima y ofrece algunas otras características útiles. Es mejor implementarlo directamente como a List<Card>
.
Ahora, para mayor comodidad, pensé que sería bueno implementarlo Iterable<Card>
, de modo que pueda usar bucles for mejorados si desea recorrerlo. (Mi Hand
clase también proporciona un get(int index)
método, por lo tanto, Iterable<Card>
está justificado en mi opinión).
La Iterable
interfaz proporciona lo siguiente (excluido 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);
}
}
Ahora puedes obtener una transmisión con:
Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);
Entonces sobre la verdadera pregunta:
- ¿Por qué
Iterable<T>
no proporciona un método predeterminado que implementestream()
yparallelStream()
no veo nada que haga esto imposible o no deseado?
Sin embargo, una pregunta relacionada que encontré es la siguiente: ¿Por qué Stream <T> no implementa Iterable <T>?
Lo cual es curiosamente lo que sugiere que lo haga al revés.
fuente
break;
una iteración? (Ok,Stream.findFirst()
podría ser una solución, pero eso no puede satisfacer todas las necesidades ...)Respuestas:
Esto no fue una omisión; hubo una discusión detallada sobre la lista de EG en junio de 2013.
La discusión definitiva del Grupo de Expertos se basa en este hilo .
Si bien parecía "obvio" (incluso para el Grupo de Expertos, inicialmente) que
stream()
parecía tener sentidoIterable
, el hecho de queIterable
fuera tan general se convirtió en un problema, porque la firma obvia:no siempre fue lo que ibas a querer. Algunas cosas que
Iterable<Integer>
preferirían que su método de flujo devuelva unIntStream
, por ejemplo. Pero poner elstream()
método tan alto en la jerarquía lo haría imposible. Entonces, en cambio, hicimos que sea realmente fácil hacer un aStream
partir de unIterable
, proporcionando unspliterator()
método. La implementación destream()
inCollection
es solo:Cualquier cliente puede obtener la transmisión que desee de un
Iterable
con:Al final concluimos que agregar
stream()
aIterable
sería un error.fuente
Iterable<Integer>
(creo que estás hablando?) Querría devolver unIntStream
. ¿Lo iterable no sería más bien unPrimitiveIterator.OfInt
? ¿O tal vez te refieres a otro caso de uso?Stream.of(Iterable)
, que al menos haría que el método fuera razonablemente reconocible al leer la documentación de la API? Como alguien que nunca ha trabajado realmente con las partes internas de Streams, nunca lo habría hecho. incluso mirado aStreamSupport
, que se describe en la documentación de proporcionar "operaciones de bajo nivel" que "en su mayoría para los escritores de la biblioteca".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:
Y luego Brian Goetz respondió :
Y después
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 :
¿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:
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?
fuente
spliterator()
deIterable
, entonces todos los problemas están solucionados, y puede implementar trivialmentestream()
yparallelStream()
..Si conoce el tamaño que podría usar
java.util.Collection
que proporciona elstream()
método:Y entonces:
Enfrenté el mismo problema y me sorprendió que mi
Iterable
implementación pudiera extenderse fácilmente a unaAbstractCollection
implementación simplemente agregando elsize()
método (por suerte tenía el tamaño de la colección :-)También debe considerar anular
Spliterator<E> spliterator()
.fuente