Java 流:按布尔谓词分为两个列表

我有一个列表。它们具有布尔字段。我想分成两个列表:和.是否可以使用流 API 执行操作?最复杂的方法是什么?employeesisActiveemployeesactiveEmployeesformerEmployees


答案 1

Collectors.partitioningBy

Map<Boolean, List<Employee>> partitioned = 
    listOfEmployees.stream().collect(
        Collectors.partitioningBy(Employee::isActive));

生成的映射包含两个列表,对应于谓词是否匹配:

List<Employee> activeEmployees = partitioned.get(true);
List<Employee> formerEmployees = partitioned.get(false);

有几个理由使用over(正如Juan Carlos Mendoza所建议的那样):partitioningBygroupingBy

首先,参数是 a(在本例中),因此有可能向它传递一个可以返回 null 的函数,这意味着如果该函数对任何雇员返回 null,则将有第 3 个分区。partitioningBy 使用谓词<Employee>,因此它只能返回 2 个分区。这将导致收集器抛出:虽然没有显式记录,但显式为空键引发异常,可能是因为Map.computeIfAbsent的行为“如果函数返回null则不记录映射”,这意味着元素将从输出中静默删除。(感谢lczapski指出这一点)。groupingByFunction<Employee, Boolean>NullPointerException

其次,在生成的映射中得到两个列表(*);;使用 ,您只能获得元素映射到给定键的键/值对:partitioningBygroupingBy

System.out.println(
    Stream.empty().collect(Collectors.partitioningBy(a -> false)));
// Output: {false=[], true=[]}

System.out.println(
    Stream.empty().collect(Collectors.groupingBy(a -> false)));
// Output: {}

(*)Java 8 Javadoc 中没有记录此行为,但它是为 Java 9 添加的。


答案 2

在这种情况下,您还可以使用分组By,因为有2个组可能性(活跃和非活跃员工):

Map<Boolean, List<Employee>> grouped = employees.stream()
                .collect(Collectors.groupingBy(Employee::isActive));

List<Employee> activeEmployees = grouped.get(true);
List<Employee> formerEmployees = grouped.get(false);