Quiero usar mapMulti en lugar de flatMap y refactoricé el siguiente código:
// using flatMap (version 1) => returns Set<Item> var items = users.stream() .flatMap(u -> u.getItems().stream()) .collect(Collectors.toSet());en esto (versión 2):
// using mapMulti (version 2) => returns Set<Item> var items = users.stream() .<Item>mapMulti((u, consumer) -> u.getItems().forEach(consumer)) .collect(Collectors.toSet()); Ambos devuelven los mismos elementos. Sin embargo, tengo dudas sobre si realmente debería reemplazar todo mi flatMap con ese código más detallado de mapMulti . ¿Por qué necesito agregar la información de tipo antes de mapMuli ( .<Item>mapMulti ). Si no incluyo la información del tipo, devolverá un Set<Object> . (¿Cómo) puedo simplificar mapMulti ?
Tenga en cuenta que el tipo de inferencia de tipos requerido para deducir el tipo de flujo resultante cuando usa flatMap es muy diferente de cuando usa mapMulti .
Cuando usa flatMap , el tipo de flujo resultante es el mismo que el tipo de retorno del cuerpo lambda. Eso es algo especial de lo que el compilador ha sido diseñado para inferir variables de tipo (es decir, el compilador "lo sabe").
Sin embargo, en el caso de mapMulti , el tipo de flujo resultante que presumiblemente desea solo se puede inferir de las cosas que hace con el parámetro lambda del consumer . Hipotéticamente, el compilador podría diseñarse de modo que, por ejemplo, si ha dicho consumer.accept(1) , entonces miraría lo que ha pasado para accept , y vería que desea un Stream<Integer> , y en el En el caso de getItems().forEach(consumer) , el único lugar de donde podría haber venido el tipo Item es el tipo de devolución de getItems , por lo que tendría que buscarlo en su lugar.
Básicamente, le está pidiendo al compilador que infiera los tipos de parámetros de una lambda, en función de los tipos de expresiones arbitrarias que contiene. El compilador simplemente no ha sido diseñado para hacer esto.
Además de agregar el prefijo <Item> , hay otras formas (más largas) de permitirle inferir un Stream<Item> como el tipo de retorno de mapMulti :
Haz que la lambda se escriba explícitamente:
var items = users.stream() .mapMulti((User u, Consumer<Item> consumer) -> u.getItems().forEach(consumer)) .collect(Collectors.toSet());Agregue una variable de flujo temporal:
// By looking at the type of itemStream, the compiler can figure out that mapMulti should return a Stream<Item> Stream<Item> itemStream = users.stream() .mapMulti((u, consumer) -> u.getItems().forEach(consumer)); var items = itemStream.collect(Collectors.toSet());No sé si esto es más "simplificado", pero creo que es más ordenado si usa referencias de métodos:
var items = users.stream() .map(User::getItems) .<Item>mapMulti(Iterable::forEach) .collect(Collectors.toSet());