Is it possible to replace the nested loop in the code below with Stream API?
Map<String, List<Role>> roleByUserUsername = roles.stream()
.collect(Collectors.groupingBy(//some foo that return userName
Role::getRoleId,
Collectors.toList()));
List<User> users = List.of(new User(), new User());
HashMap<String, User> userByRoleId = new HashMap<>();
for (final User user : users) {
for (final Role roles1 : roleByUserUsername.get(user.getPassword())) {
userByRoleId.put(roles1.getRoleId(), user);
}
}
CodePudding user response:
Try this
users.stream().forEach(user->roleByUserUsername.get(user.getPassword()).forEach(role->userByRoleId.put(role.getRoleId(), user)));
CodePudding user response:
You need to flatten the list of roles obtained from the map roleByUsername
.
By the way, there is an inconsistency: according to its name the map is meant to contain usernames as keys, but in the loop you're accessing it by providing the result returned by the call getPassword()
.
Then you need to apply collect
as a terminal operation and provide collector toMap()
as an argument in order to generate a map which associates roleId
with a single user.
List<Role> roles = // initialing the list of roles
Map<String, List<Role>> roleByUsername = roles.stream()
.collect(Collectors.groupingBy(Role::getRoleId));
List<User> users = List.of(new User(), new User());
Map<String, User> userByRoleId = users.stream()
.flatMap(user -> roleByUsername.get(user.getPassword()).stream()
.map(role -> Map.entry(role.getRoleId(), user)))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
But there's a logical problem here. Assuming that roleId
is unique for every role, but there could multiple users having the same role. Unless you have designed an application where every user has a unique role.
Therefore, it makes sense to change the map type to Map<String, List<User>>
so that a collection of user would be mapped to each roleId
.
And to achieve that, we need to change the collector from toMap
to groupingBy()
in conjunction with mapping()
and toList()
.
Map<String, List<User>> userByRoleId = users.stream()
.flatMap(user -> roleByUsername.get(user.getPassword()).stream()
.map(role -> Map.entry(role.getRoleId(), user)))
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())
));
Sidenotes:
Collector
groupingBy()
has a flavor that expects only one argument -classifier
function. It will store all elements mapped to the same key into a list by default. You don't need to providetoList()
as a downstream.Write your code against interfaces like
Map
, don't make it dependent on concrete implementations: What does it mean to "program to an interface"?