Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

204
Vistas
Why does mapMulti need type information in comparison to flatMap

I want to use mapMulti instead of flatMap and refactored the following code:

// using flatMap (version 1) => returns Set<Item>
var items = users.stream()
                 .flatMap(u -> u.getItems().stream())
                .collect(Collectors.toSet());

into this (version 2):

// using mapMulti (version 2) => returns Set<Item>
var items = users.stream()
                 .<Item>mapMulti((u, consumer) -> u.getItems().forEach(consumer))
                 .collect(Collectors.toSet());

Both return the same elements. However, I am in doubt if I should really replace all my flatMap with that more verbose code of mapMulti. Why do I need to add the type information before mapMuli (.<Item>mapMulti). If I don't inlcude the type information, it will return a Set<Object>. (How) can I simplify mapMulti?

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Notice that the kind of type inference required to deduce the resulting stream type when you use flatMap, is very different from that when you use mapMulti.

When you use flatMap, the type of the resulting stream is the same type as the return type of the lambda body. That's a special thing that the compiler has been designed to infer type variables from (i.e. the compiler "knows about" it).

However, in the case of mapMulti, the type of the resulting stream that you presumably want can only be inferred from the things you do to the consumer lambda parameter. Hypothetically, the compiler could be designed so that, for example, if you have said consumer.accept(1), then it would look at what you have passed to accept, and see that you want a Stream<Integer>, and in the case of getItems().forEach(consumer), the only place where the type Item could have come from is the return type of getItems, so it would need to go look at that instead.

You are basically asking the compiler to infer the parameter types of a lambda, based on the types of arbitrary expressions inside it. The compiler simply has not been designed to do this.

Other than adding the <Item> prefix, there are other (longer) ways to let it infer a Stream<Item> as the return type of mapMulti:

Make the lambda explicitly typed:

var items = users.stream()
             .mapMulti((User u, Consumer<Item> consumer) -> u.getItems().forEach(consumer))
             .collect(Collectors.toSet());

Add a temporary stream variable:

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

I don't know if this is more "simplified", but I think it is neater if you use method references:

var items = users.stream()
             .map(User::getItems)
             .<Item>mapMulti(Iterable::forEach)
             .collect(Collectors.toSet());
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda