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

Rud*_*koŭ 15 java collections reduce functional-programming java-stream

我有一份清单employees.他们有isActive布尔字段.我想employees分成两个列表:activeEmployeesformerEmployees.是否可以使用Stream API?什么是最复杂的方式?

And*_*ner 20

Collectors.partitioningBy:

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

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

List<Employee> activeEmployees = partitioned.get(true);
List<Employee> formerEmployees = partitioned.get(false);
Run Code Online (Sandbox Code Playgroud)

有几个原因,使用partitioningBygroupingBy(由所建议的胡安·卡洛斯·门多萨):

首先,参数groupingBy是a Function<Employee, Boolean>(在这种情况下),因此有可能向它传递一个可以返回null的函数,这意味着如果该函数为任何一个雇员返回null,则会有第三个分区.partitioningBy使用a Predicate<Employee>,所以它只能返回2个分区.

其次,在得到的地图中得到两个列表(*)NullPointerException; 使用Map.computeIfAbsent,您只获得键/值对,其中元素映射到给定键:

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

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

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


Jua*_*oza 5

在这种情况下,您还可以使用groupingBy,因为有 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);
Run Code Online (Sandbox Code Playgroud)

  • +1,但请注意,使用这种方法时应该*稍微*小心:`groupingBy` 的参数是一个 `Function&lt;Employee, Boolean&gt;`,因此有可能向它传递一个可以返回 `null 的函数`,这意味着如果该函数为任何员工返回 null,则将有第三个分区。`partitioningBy` 使用 `Predicate`,因此它只能返回 2 个分区。 (5认同)

Adr*_*ian 5

最尖端的方法是什么?

Java 12 当然有新的Collectors::teeing

List<List<Employee>> divided = employees.stream().collect(
      Collectors.teeing(
              Collectors.filtering(Employee::isActive, Collectors.toList()),
              Collectors.filtering(Predicate.not(Employee::isActive), Collectors.toList()),
              List::of
      ));

System.out.println(divided.get(0));  //active
System.out.println(divided.get(1));  //inactive
Run Code Online (Sandbox Code Playgroud)