我有
Employee
对象,其中包含 3
字段:name
、role
、companyName
。
我需要根据
Employee
属性过滤 role
对象。
尽管我在下面的代码中的流中应用了
filter
,但它返回了整个数据。
我的代码:
public static Map<String, List<? extends Employee>> testMappingFilter(List<Employee> emp) {
Map<String, List<? extends Employee>> dataInput = new HashMap<>();
for (Employee entry : emp) {
dataInput.put("senior", new ArrayList(emp));
dataInput.put("junior", new ArrayList(emp));
}
Map<String, List<? extends Employee>> dataResponse = new HashMap<>();
Set<String> realmroles = new HashSet<>();
realmroles.add("admin");
realmroles.add("user");
Either<Map<String, List<? extends Employee>>, ResponseFormat> followedResourcesServices = Either.left(dataInput);
realmroles.stream().forEach(role ->
followedResourcesServices.left().value().entrySet().stream()
.filter(elements -> elements.getValue().stream().anyMatch(i -> ((Employee) i).getRole().contains(role)))
.forEach(elements -> dataResponse.put(elements.getKey(), elements.getValue())));
return dataResponse;
}
样本数据:
预期输出:
(预期角色只有
"admin"
和"user"
,与角色"super"
相关的数据应该不会来)
{ “senior” :
[ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
{ ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
{ ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ],
“junior” :
[ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
{ ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
{ ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ]
}
实际产量:
{ “senior” :
[ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
{ ”name”:”DDD”, “role”:”super”, “companyName”:”DDD &Co” },
{ ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
{ ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ],
“junior” :
[ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
{ ”name”:”DDD”, “role”:”super”, “companyName”:”DDD &Co” },
{ ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
{ ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ]
}
您的代码中有几个问题:
过滤逻辑不正确:您说您只需要保留角色
"admin"
和"user"
,但根据您的代码,List
中的任何Employee
包含至少一名具有这些角色的员工都是好的去(意味着“整个”列表,而不仅仅是具有所需角色的员工)。这就是为什么您会在输出中看到角色 ”super”
。您需要过滤每个list中的employees,而不是过滤lists。
Stream.forEach
的工作,它通过
副作用运作。 不鼓励使用它来代替归约操作。查看 API 文档,特别注意代码示例。
Set
检查,而不是迭代角色的
contains()
,并仅迭代您通过调用 Either.left(dataInput).value()
检索的映射条目。
collect()
,因为我们需要执行可变归约。
在这种情况下,我们无法在不创建新对象的情况下在流中应用过滤逻辑(这会降低性能),或者不改变现有数据(即使您不再需要它,这也不是正确的方法,因为改变流中的对象违反了函数式编程范式)。 我们的另一个选择是在累积数据时在
Collector
内执行过滤。我会继续做下去。
为了生成结果图,我们可以使用 collector与作为下游应用的
flatMapping()
+
toList()
结合使用。这就是它的实现方式:
Map<String, List<? extends Employee>> dataInput = // initializing dataInput
Set<String> realmroles = // initializing realmroles
return Either.left().value().entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.flatMapping(entry -> entry.getValue().stream()
.filter(emp -> realmroles.contains(((Employee) emp).getRole())),
Collectors.toList())
));
followedResourcesServices.left().value().entrySet().stream().forEach(e -> {
e.setValue(e.getValue().stream().filter(i -> realmroles.stream().anyMatch(role -> ((Employee) i).getRole().equals(role))).
collect(Collectors.toList()));
dataResponse.put(e.getKey(), e.getValue());
});