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.


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.


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.


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

¡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());

¿Cuántas veces quieres agregar un elemento? : D Onza por flujo o una vez por elemento en el flujo original?
user482745
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.