Nir*_*ane 22 java java-8 java-stream collectors java-9
如何先分组,然后使用Java流应用过滤?
示例:考虑此类Employee
:我希望按部门分组,其中包含薪水大于2000的员工列表.
public class Employee {
private String department;
private Integer salary;
private String name;
//getter and setter
public Employee(String department, Integer salary, String name) {
this.department = department;
this.salary = salary;
this.name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我如何做到这一点
List<Employee> list = new ArrayList<>();
list.add(new Employee("A", 5000, "A1"));
list.add(new Employee("B", 1000, "B1"));
list.add(new Employee("C", 6000, "C1"));
list.add(new Employee("C", 7000, "C2"));
Map<String, List<Employee>> collect = list.stream()
.filter(e -> e.getSalary() > 2000)
.collect(Collectors.groupingBy(Employee::getDepartment));
Run Code Online (Sandbox Code Playgroud)
产量
{A=[Employee [department=A, salary=5000, name=A1]],
C=[Employee [department=C, salary=6000, name=C1], Employee [department=C, salary=7000, name=C2]]}
Run Code Online (Sandbox Code Playgroud)
因为B部门的员工薪水不超过2000.所以B部门没有关键:但实际上,我想把那个钥匙放在 空列表中 -
预期产出
{A=[Employee [department=A, salary=5000, name=A1]],
B=[],
C=[Employee [department=C, salary=6000, name=C1], Employee [department=C, salary=7000, name=C2]]}
Run Code Online (Sandbox Code Playgroud)
我们应该怎么做?
Nam*_*man 24
您可以使用Collectors.filtering
Java-9中引入的API:
Map<String, List<Employee>> output = list.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.filtering(e -> e.getSalary() > 2000, Collectors.toList())));
Run Code Online (Sandbox Code Playgroud)
API说明中的重要内容:
filter()收集器在多级缩减中使用时非常有用,例如a
groupingBy
或者下游partitioningBy
.过滤收集器与流的
filter()
操作不同.
Hol*_*ger 18
nullpointer的答案显示了直截了当的方式.如果你不能更新到Java 9,没问题,这个filtering
收藏家没有魔力.这是Java 8兼容版本:
public static <T, A, R> Collector<T, ?, R> filtering(
Predicate<? super T> predicate, Collector<? super T, A, R> downstream) {
BiConsumer<A, ? super T> accumulator = downstream.accumulator();
return Collector.of(downstream.supplier(),
(r, t) -> { if(predicate.test(t)) accumulator.accept(r, t); },
downstream.combiner(), downstream.finisher(),
downstream.characteristics().toArray(new Collector.Characteristics[0]));
}
Run Code Online (Sandbox Code Playgroud)
您可以将它添加到代码库中,并以与Java 9相同的方式使用它,因此如果您正在使用,则无需以任何方式更改代码import static
.
使用Map#putIfAbsent(K,V)
过滤后,填补了国内空白
Map<String, List<Employee>> map = list.stream()
.filter(e->e.getSalary() > 2000)
.collect(Collectors.groupingBy(Employee::getDepartment, HashMap::new, toList()));
list.forEach(e->map.putIfAbsent(e.getDepartment(), Collections.emptyList()));
Run Code Online (Sandbox Code Playgroud)
注意:由于groupingBy返回的地图不保证是可变的,因此您需要指定一个地图供应商以确保(感谢shmosel指出这一点).
另一个(不推荐)解决方案是使用toMap
而不是groupingBy
,它具有为每个Employee创建临时列表的缺点.它看起来有点乱
Predicate<Employee> filter = e -> e.salary > 2000;
Map<String, List<Employee>> collect = list.stream().collect(
Collectors.toMap(
e-> e.department,
e-> new ArrayList<Employee>(filter.test(e) ? Collections.singleton(e) : Collections.<Employee>emptyList()) ,
(l1, l2)-> {l1.addAll(l2); return l1;}
)
);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7307 次 |
最近记录: |