开发过程中,有时会遇到需要根据某些条件对集合中的元素分组为满足和不满足条件两组。
比如根据年龄是否大于18岁这个条件将用户分为18岁以下和18岁以上两组,又或者根据是否为负数将一组数字分为负数和非负数两组。

这个时候,可以使用Stream流中的partitioningBy很方便的进行条件分组。

partitioningBy是java.util.stream.Collectors类的方法,有以下两个重载方法:

public static <T>
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)

public static <T, D, A>
Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
                                                Collector<? super T, A, D> downstream)

其中:
predicate参数为谓词表达式,即我们判断的条件。
downstream为收集器,可以将结果通过该收集器转为其它类型的集合。

使用代码示例:
首先我们定义一个用户类:

@Data
public class User{
    private String id;
    private String name;
    private int age;
}

接着我们定义一个用户集合:

User user0 = new User("a0", "user0", 21);
User user1 = new User("a1", "user1", 16);
User user2 = new User("a2", "user2", 34);
User user3 = new User("a2", "user2", 41);
User user4 = new User("a1", "user1", 16);
List<User> userList = Arrays.asList(user0, user1, user2, user3, user4);

现在,我们想根据年龄是否大于18岁对list进行分组,那么,我们可以这样写,其中value.getAge() >= 18即为条件:

Map<Boolean, List<User>> collect = userList.stream()
        .collect(Collectors.partitioningBy(value -> value.getAge() >= 18));

System.out.println(collect);

则输出的结果为:

{false=[User{id='a1', name='user1', age=16}, User{id='a1', name='user1', age=16}], true=[User{id='a0', name='user0', age=21}, User{id='a2', name='user2', age=34}, User{id='a2', name='user2', age=41}]}

可以看到,根据我们传入的条件:value.getAge() >= 18,将用户集合分成了满足以及不满足两组,即大于等于18岁与小于18岁两组。

但是我们发现,原集合中存在一些字段相同的用户,我们想对结果去重,就可以使用partitioningBy的第二个重载方法,通过收集器,将结果转换成Set,进行初步去重:

Map<Boolean, Set<User>> distinct = userList.stream()
        .collect(Collectors.partitioningBy(value -> value.getAge() >= 18, 
                Collectors.toSet()));
System.out.println(distinct);

输出的结果为:

{false=[User{id='a1', name='user1', age=16}], true=[User{id='a2', name='user2', age=34}, User{id='a0', name='user0', age=21}, User{id='a2', name='user2', age=41}]}

不难看出,对于 {id='a1', name='user1', age=16} 这个用户,已经成功去重。

也可以参考之前的文章:使用Stream流对List中的Map进行多条件去重 对于任意字段进行去重,比如想要根据id与name两个字段进行去重,则可以这样写:

//结果放在list中
Map<Boolean, List<User>> partitionList = userList.stream()
        .collect(Collectors.partitioningBy(value -> value.getAge() >= 18,
                Collectors.collectingAndThen(
                        Collectors.toCollection(() ->
                                new TreeSet<>(Comparator.comparing(value -> value.getId() + ";" + value.getName()))),
                        ArrayList::new)));

//结果放在set中
Map<Boolean, Set<User>> partitionSet = userList.stream()
        .collect(Collectors.partitioningBy(value -> value.getAge() >= 18,
                Collectors.toCollection(() ->
                        new TreeSet<>(Comparator.comparing(value -> value.getId() + ";" + value.getName())))));

输出的结果为:

{false=[User{id='a1', name='user1', age=16}], true=[User{id='a0', name='user0', age=21}, User{id='a2', name='user2', age=34}]}

可以看出,对于 {id='a1', name='user1'}{id='a2', name='user2'} 这些用户,都已经成功去重。

Q.E.D.