Issue
Let's say you have an interface, a couple of implementation classes and an Enum like this: Interface:
public interface Employee {
// No two employees will have same favorite hobbies
List<Hobby> favoriteHobbies;
}
Implementations:
public class Employee1 implements Employee {
@Override
public List<Hobby> favoriteHobbies {
return List.of(Hobbies.swimming, Hobbies.dancing);
}
}
public class Employee2 implements Employee {
@Override
public List<Hobby> favoriteHobbies {
return List.of(Hobbies.running);
}
}
Enum:
public enum Hobby {
swimming,
running,
dancing
}
I have
List<Employee> employees = List.of(Employee1, Employee2);
And using Streams, I want to Stream through employees
list and again Stream through each Employee object's favoriteHobbies()
and create a Map<Hobby, Employee>
like below:
"swimming" -> "Employee1"
"dancing" -> "Employee1"
"running" -> "Employee2"
Solution
I would create a Map.Entry
in a Stream
and then collect it using its keys and values
Since java-16 this is possible using Stream#mapMulti
Map<Hobby, Employee> map = employees.stream()
.mapMulti((Employee employee, Consumer<AbstractMap.SimpleEntry<Hobby, Employee>> consumer) -> {
employee.favoriteHobbies().forEach(hobby -> {
consumer.accept(new AbstractMap.SimpleEntry<>(hobby, employee));
});
})
.collect(Collectors.toMap(
AbstractMap.SimpleEntry::getKey,
AbstractMap.SimpleEntry::getValue,
(entryOne, entryTwo) -> entryOne // or whatever, maybe even throw new XXXException()
));
Before java-16 this is possible with a Stream#flatMap
and Collectors#toMap
Map<Hobby, Employee> map = employees.stream()
.flatMap(employee -> employee.favoriteHobbies()
.stream()
.map(hobby -> new AbstractMap.SimpleEntry<>(hobby, employee)))
.collect(Collectors.toMap(
AbstractMap.SimpleEntry::getKey,
AbstractMap.SimpleEntry::getValue,
(entryOne, entryTwo) -> entryOne // or whatever, maybe even throw new XXXException()
));
Which produces
Answered By - Yassin Hajaj
Answer Checked By - Katrina (JavaFixing Volunteer)