Añadiendo nuevo valor a Stream existente

79

¿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.collecty me pregunto por qué. Gracias por adelantado.

Dmytro
fuente
2
No hay garantía de que lo Listdevuelto sea collect(Collectors.toList())compatible add, puede usarlo Collectors.toCollectionpara elegir el tipo de lista que obtiene.
Alex - GlassEditor.com

Respuestas:

97

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 Ty 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.

Brian Goetz
fuente
7
¿El método no debería llamarse "appendToStream"? De lo contrario, creo que los parámetros del método concat deberían cambiarse.
Andrea Polci
concatEl 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.
TongChen
34

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.

Eran
fuente
Tenga cuidado al construir transmisiones a partir de concatenaciones repetidas. Acceder a un elemento de una secuencia profundamente concatenada puede resultar en cadenas de llamadas profundas, o incluso StackOverflowException.
TongChen
5

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:

first
second
third
artspb
fuente
¡Agradable! Aunque, otra biblioteca.
GhostCat
0

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:

    stream.flatMap(e -> Stream.of(e, element))
            .map(...)
            .filter(...)
            .collect(Collectors.toList());
Solubris
fuente
¿Cuántas veces quieres agregar un elemento? : D Onza por flujo o una vez por elemento en el flujo original?
user482745