我正在尝试将嵌套的for循环转换为java 8流。
循环实施
private Set<String> getAllowRolesFromInheritedPolicy(String userId, List<Policy> allowedPoliciesThisCustomer) {
Set<String> allowedRolesThisUser = Sets.newHashSet();
for (Policy policy : allowedPoliciesThisCustomer) {
Map<String, Role> roles = policy.getRoles();
for (Role role : roles.values()) {
if (role.getUsers().contains(userId)) {
allowedRolesThisUser.add(role.getRoleName());
}
}
}
在代码role.getUsers()
中返回List<String>
。
流程实施
我正在尝试将for循环更改为java 8流:
Set<String> allowedRolesThisUser = Sets.newHashSet(allowedPoliciesThisCustomer.stream()
.map(policy -> policy.getRoles().values())
.filter(role -> role.getUsers().contains(userId))
.collect(Collectors.toList()));
但是编译器说:
error: cannot find symbol : .filter(role -> role.getUsers().contains(userId))
symbol: method getUsers(), location: variable role of type Collection<Role>
Role
有getUsers
函数,Collection<Role>
没有。我该怎么做才能使转换正确?
谢谢。
答案 0 :(得分:7)
<强>解决方案强>
private static Set<String> streamImplementation(final String userId,
final List<Policy> allowedPoliciesThisCustomer) {
return allowedPoliciesThisCustomer.stream()
.map(Policy::getRoles)
.map(Map::values)
.flatMap(Collection::stream)
.filter(r -> r.getUsers().contains(userId))
.map(Role::getRoleName)
.collect(Collectors.toSet());
}
<强>解释强>
获取地图中的值后,您需要展平地图。这在以下两行中完成
.map(Map::values)
.flatMap(Collection::stream)
这可以确保Role
类型正确结转。
完整SSCCE
package com.stackoverflow;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static me.karun.Policy.policy;
import static me.karun.Role.role;
import static org.assertj.core.api.Assertions.assertThat;
public class PoliciesTest {
@Test
public void streamImplementation_whenComparedWithALoopImplementation_thenShouldReturnTheSameResult() {
final String userId = "user-1";
final Role role1 = role("role-1", "user-1", "user-2");
final Role role2 = role("role-2", "user-1", "user-3");
final Role role3 = role("role-3", "user-2", "user-3");
final Role role4 = role("role-4", "user-3", "user-4");
final List<Policy> allowedPoliciesThisCustomer = asList(
policy(role1, role2),
policy(role3, role4)
);
final Set<String> oldResult = loopImplementation(userId, allowedPoliciesThisCustomer);
final Set<String> newResult = streamImplementation(userId, allowedPoliciesThisCustomer);
assertThat(newResult).isEqualTo(oldResult);
}
private static Set<String> streamImplementation(final String userId, final List<Policy> allowedPoliciesThisCustomer) {
return allowedPoliciesThisCustomer.stream()
.map(Policy::getRoles)
.map(Map::values)
.flatMap(Collection::stream)
.filter(r -> r.getUsers().contains(userId))
.map(Role::getRoleName)
.collect(toSet());
}
private static Set<String> loopImplementation(final String userId, final List<Policy> allowedPoliciesThisCustomer) {
final Set<String> allowedRolesThisUser = new HashSet<>();
for (final Policy policy : allowedPoliciesThisCustomer) {
final Map<String, Role> roles = policy.getRoles();
for (final Role role : roles.values()) {
if (role.getUsers().contains(userId)) {
allowedRolesThisUser.add(role.getRoleName());
}
}
}
return allowedRolesThisUser;
}
}
@RequiredArgsConstructor
@Getter
class Policy {
private final Map<String, Role> roles;
static Policy policy(final Role... roles) {
final Map<String, Role> rolesMap = stream(roles)
.collect(toMap(Role::getRoleName, identity()));
return new Policy(rolesMap);
}
}
@RequiredArgsConstructor
@Getter
class Role {
private final List<String> users;
private final String roleName;
static Role role(final String roleName, final String... users) {
return new Role(asList(users), roleName);
}
}
答案 1 :(得分:4)
试试这个。
private Set<String> getAllowRolesFromInheritedPolicy(String userId, List<Policy> allowedPoliciesThisCustomer) {
return allowedPoliciesThisCustomer.stream()
.flatMap(policy -> policy.getRoles().values().stream())
.filter(role -> role.getUsers().contains(userId))
.map(Role::getRoleName)
.collect(Sets::newHashSet, (set, e) -> set.add(e), (a, b) -> a.addAll(b));
}