procesamiento - stream java 8 ejemplo
¿Es posible emitir un Stream en Java 8? (4)
¿Es posible emitir una secuencia en Java 8? Supongamos que tengo una lista de objetos, puedo hacer algo como esto para filtrar todos los objetos adicionales:
Stream.of(objects).filter(c -> c instanceof Client)
Sin embargo, después de esto, si quiero hacer algo con los clientes, debería lanzar cada uno de ellos:
Stream.of(objects).filter(c -> c instanceof Client)
.map(c -> ((Client) c).getID()).forEach(System.out::println);
Esto se ve un poco feo. ¿Es posible emitir una transmisión completa a un tipo diferente? ¿Como arrojar Stream<Object>
a Stream<Client>
?
Por favor, ignore el hecho de que hacer cosas como esta probablemente signifique un mal diseño. Hacemos cosas como esta en mi clase de ciencias de la computación, así que estaba investigando las nuevas características de java 8 y tenía curiosidad si esto era posible.
Esto se ve un poco feo. ¿Es posible emitir una transmisión completa a un tipo diferente? ¿Como arrojar
Stream<Object>
aStream<Client>
?
No, eso no sería posible. Esto no es nuevo en Java 8. Esto es específico de los genéricos. Una List<Object>
no es un super tipo de List<String>
, por lo que no puede simplemente convertir una List<Object>
en una List<String>
.
Similar es el problema aquí. No puede convertir Stream<Object>
en Stream<Client>
. Por supuesto, puedes lanzarlo indirectamente así:
Stream<Client> intStream = (Stream<Client>) (Stream<?>)stream;
pero eso no es seguro, y puede fallar en tiempo de ejecución. La razón subyacente para esto es que los genéricos en Java se implementan usando borrado. Entonces, no hay información de tipo disponible sobre qué tipo de Stream
es en tiempo de ejecución. Todo es solo Stream
.
Por cierto, ¿qué pasa con su enfoque? Luce bien para mi.
En la línea de la respuesta de ggovan , hago esto de la siguiente manera:
/**
* Provides various high-order functions.
*/
public final class F {
/**
* When the returned {@code Function} is passed as an argument to
* {@link Stream#flatMap}, the result is a stream of instances of
* {@code cls}.
*/
public static <E> Function<Object, Stream<E>> instancesOf(Class<E> cls) {
return o -> cls.isInstance(o)
? Stream.of(cls.cast(o))
: Stream.empty();
}
}
Usando esta función auxiliar:
Stream.of(objects).flatMap(F.instancesOf(Client.class))
.map(Client::getId)
.forEach(System.out::println);
No creo que exista una manera de hacerlo así fuera de la caja. Una solución posiblemente más limpia sería:
Stream.of(objects)
.filter(c -> c instanceof Client)
.map(c -> (Client) c)
.map(Client::getID)
.forEach(System.out::println);
o, como se sugiere en los comentarios, puede usar el método de conversión; sin embargo, el primero puede ser más fácil de leer:
Stream.of(objects)
.filter(Client.class::isInstance)
.map(Client.class::cast)
.map(Client::getID)
.forEach(System.out::println);
Tarde a la fiesta, pero creo que es una respuesta útil.
flatMap
sería la forma más rápida de hacerlo.
Stream.of(objects).flatMap(o->(o instanceof Client)?Stream.of((Client)o):Stream.empty())
Si o
es un Client
entonces cree un Stream con un solo elemento, de lo contrario, use el flujo vacío. Estas secuencias se aplanarán en una Stream<Client>
.