employees
のリストがあります。それらにはisActive
ブール型フィールドがあります。 employees
をactiveEmployees
とformerEmployees
の2つのリストに分けたいと思います。 Stream APIを使用して行うことはできますか?最も洗練された方法は何ですか?
Map<Boolean, List<Employee>> partitioned =
listOfEmployees.stream().collect(
Collectors.partitioningBy(Employee::isActive));
結果のマップには、述語が一致したかどうかに対応する2つのリストが含まれます。
List<Employee> activeEmployees = partitioned.get(true);
List<Employee> formerEmployees = partitioned.get(false);
partitioningBy
をgroupingBy
よりも使用する理由はいくつかあります( Juan Carlos Mendoza によって示唆されています):
まず、groupingBy
のパラメーターはFunction<Employee, Boolean>
(この場合)であり、nullを返すことができる関数を渡す可能性があります。 つまり、その関数がいずれかの従業員に対してnullを返す場合、3番目のパーティションが存在することになります。 これにより、コレクターによってpartitioningBy
はPredicate<Employee>
を使用するため、2つのパーティションのみを返すことができます。NullPointerException
がスローされます。明示的に文書化されていませんが、おそらく Map.computeIfAbsent
の動作が原因で、nullキーに対して例外が明示的にスローされます。 「関数がnullを返す場合、マッピングは記録されません」、つまり、要素が出力から黙って削除されることを意味します。 (これを指摘してくれた lczapski に感謝します)。
次に、partitioningBy
を使用して、結果のマップで2つのリスト(*)を取得します。 groupingBy
を使用すると、要素が指定されたキーにマップされているキー/値のペアのみが取得されます。
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 で追加されました。
最も洗練された方法は何ですか?
もちろん、Java 12と新しいCollectors::teeing
List<List<Emploee>> divided = employees.stream().collect(
Collectors.teeing(
Collectors.filtering(Emploee::isActive, Collectors.toList()),
Collectors.filtering(Predicate.not(Emploee::isActive), Collectors.toList()),
List::of
));
System.out.println(divided.get(0)); //active
System.out.println(divided.get(1)); //inactive
この場合、 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);
サードパーティのライブラリを使用する場合、これは _Collectors2.partition
_ from Eclipse Collections を使用して機能します。
_PartitionMutableList<Employee> partition =
employees.stream().collect(
Collectors2.partition(Employee::isActive, PartitionFastList::new));
List<Employee> activeEmployees = partition.getSelected();
List<Employee> formerEmployees = partition.getRejected();
_
ListIterate
を使用して物事を簡略化することもできます。
_PartitionMutableList<Employee> partition =
ListIterate.partition(employees, Employee::isActive);
List<Employee> activeEmployees = partition.getSelected();
List<Employee> formerEmployees = partition.getRejected();
_
PartitionMutableList
は PartitionIterable
から拡張されるタイプです。 PartitionIterable
のすべてのサブタイプには、肯定的な結果getSelected()
と否定的な結果getRejected()
のコレクションがあります。
注:私はEclipseコレクションのコミッターです。