¿Existe una buena manera de agregar un nuevo valor a lo existente Stream
? Todo lo que puedo imaginar es algo como esto:
public <T> Stream<T> addToStream(Stream<T> stream, T elem ) {
List<T> result = stream.collect(Collectors.toList());
result.add(elem);
return result.stream();
}
Pero estoy buscando algo más conciso que pueda usar en expresiones lambda sin verbosidad.
Otra pregunta apareció cuando intenté implementar el principio PECS :
public <T> Stream<? super T> addToStream(Stream<? super T> stream, T elem ) {
List<? super T> result = stream.collect(Collectors.toList()); //error
result.add(elem);
return result.stream();
}
Parece que el comodín no funciona con Stream.collect
y me pregunto por qué. Gracias por adelantado.
List
devuelto seacollect(Collectors.toList())
compatibleadd
, puede usarloCollectors.toCollection
para elegir el tipo de lista que obtiene.Respuestas:
La pregunta contradice una suposición incorrecta: que los flujos realmente contienen sus datos. Ellos no; Los flujos no son estructuras de datos, son un medio para especificar operaciones masivas en una variedad de fuentes de datos.
Hay combinadores para combinar dos flujos en uno, como
Stream.concat
, y fábricas para crear flujos a partir de un conjunto de elementos conocidos (Stream.of
) o de colecciones (Collection.stream
). Por lo tanto, puede combinarlos si desea producir una nueva secuencia que sea la concatenación de la secuencia que tiene en la mano, junto con una nueva secuencia que describa los nuevos elementos.El problema en su ejemplo de PECS es que tiene tres apariciones de
? super T
y está asumiendo que describen el mismo tipo, pero no es así. Cada aparición de un comodín corresponde a una captura única, que no es lo que desea; debe darle un nombre a esa variable de tipo para que el compilador sepa que el tipo de la lista y el tipo de flujo de entrada son iguales. (Además, no materialice una colección; eso es caro y potencialmente no termina si el flujo no es finito. Simplemente use concat.) Entonces la respuesta es: simplemente se equivocó con los genéricos. He aquí una forma de hacerlo:public<T> Stream<T> appendToStream(Stream<? extends T> stream, T element) { return Stream.concat(stream, Stream.of(element)); }
Te confundiste con PECS porque estabas pensando en "insertar" en el flujo, cuando en realidad estás consumiendo de él.
fuente
concat
El método puede usar, pero no demasiado, de javadoc: Tenga cuidado al construir flujos a partir de concatenaciones repetidas. Acceder a un elemento de una secuencia profundamente concatenada puede resultar en cadenas de llamadas profundas, o incluso StackOverflowException.Qué tal si
return Stream.concat(stream, Stream.of(elem));
esto asumiendo que el Stream original es finito. Si no es así, puede combinarlos en orden inverso.
fuente
La biblioteca StreamEx tiene métodos
#prepend()
y correspondientes#append()
. A continuación, se muestra un ejemplo de cómo se pueden utilizar:StreamEx.of("second").prepend("first").append("third").forEach(System.out::println);
Un resultado es el siguiente:
fuente
La mejor manera es usar un mapa plano de la siguiente manera:
public <T> Stream<T> appendToStream(Stream<T> stream, T element) { return stream.flatMap(e -> Stream.of(e, element)); }
Esto opera en el flujo original, por lo que puede ser solo otra operación intermedia en el flujo, por ejemplo:
fuente