java8提取list中对象有相同属性值的对象或属性值

准备数据

java 复制代码
// 原始列表
List<Person> persons = Arrays.asList(new Person("li", 34, "135555"), new Person("jiang", 33, "1366666"), new Person("yang", 22, "135555"), new Person("huang", 32, "1366666"), new Person("han", 31, "1376666")); 
java 复制代码
    @Data
    public static class Person {
        private String name;
        private int age;
        private String phoneNumber;

        public Person(String name, int age, String phoneNumber) {
            this.name = name;
            this.age = age;
            this.phoneNumber = phoneNumber;
        }

    }

方式一、使用Collectors.groupingBy按属性分组后筛选计数大于1的条目

根据单个属性提取重复对象

java 复制代码
List<Person> list =
                persons.stream()
.collect(Collectors.groupingBy(Person::getPhoneNumber,Collectors.toList()))
                        .values()
                        .stream()
                        .filter(group -> group.size() > 1)
                        .flatMap(List::stream)
                        .collect(Collectors.toList());

        System.out.println(JSON.toJSONString(list));

根据多个属性提取重复对象

通过自定义组合键实现多属性去重:

java 复制代码
List<Person> duplicates = persons.stream()
    .collect(Collectors.groupingBy(
        p -> Arrays.asList(p.getName(), p.getAge()),
        Collectors.toList()
    ))
    .values().stream()
    .filter(group -> group.size() > 1)
    .flatMap(List::stream)
    .collect(Collectors.toList());

转为map

这会返回属性值(如phoneNumber)与对应对象列表的Map,其中value.size()>1表示该属性值重复

java 复制代码
Map<String, List<Person>> map = persons.stream()
                .collect(Collectors.groupingBy(Person::getPhoneNumber))
                .entrySet()
                .stream()
                .filter(entry -> entry.getValue().size() > 1)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        System.out.println(JSON.toJSONString(map));

提取重复属性值:转为字符串"1,2,3,4"的形式

java 复制代码
String duplicates =
                persons.stream()
                        .collect(Collectors.groupingBy(Person::getPhoneNumber, Collectors.toList()))
                        .entrySet()
                        .stream()
                        .filter(en -> en.getValue().size() > 1)
                        .map(Map.Entry::getKey)
                        .collect(Collectors.joining(","));
        System.out.println(duplicates);

方式二、使用toMap计数过滤。

结合Collectors.toMap统计出现次数:

直接返回重复的属性值列表

java 复制代码
List<String> duplicateValues = persons.stream()
                .collect(Collectors.toMap(
                        Person::getPhoneNumber,
                        e -> 1,
                        Integer::sum
                ))
                .entrySet()
                .stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        System.out.println(duplicateValues);

提取重复属性值:转为字符串"1,2,3,4"的形式

java 复制代码
String dupNumbers = persons.stream()
                    .collect(Collectors.toMap(
                            Person::getPhoneNumber,
                            e -> 1,
                            Integer::sum
                    ))
                    .entrySet()
                    .stream()
                    .filter(entry -> entry.getValue() > 1)
                    .map(Map.Entry::getKey)
                    .collect(Collectors.joining(","));

方式三、根据特定属性去重。

若需基于属性去重而非提取重复值,可用:

通过TreeSet按phoneNumber去重

java 复制代码
List<Person> distinct = persons.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(
                                () -> new TreeSet<>(Comparator.comparing(Person::getPhoneNumber))
                        ),
                        ArrayList::new
                ));
        System.out.println(distinct);

完整代码示例:

java 复制代码
public static void main(String[] args) {
    // 原始列表
    List<Person> persons = Arrays.asList(new Person("li", 34, "135555"), new Person("jiang", 33, "1366666"), new Person("yang", 22, "135555"), new Person("huang", 32, "1366666"), new Person("han", 31, "1376666")); 
    //方式一、使用Collectors.groupingBy按属性分组后筛选计数大于1的条目
    List<Person> list =
                persons.stream()
.collect(Collectors.groupingBy(Person::getPhoneNumber,Collectors.toList()))
                        .values()
                        .stream()
                        .filter(group -> group.size() > 1)
                        .flatMap(List::stream)
                        .collect(Collectors.toList());

        System.out.println(JSON.toJSONString(list));

//转为map,这会返回属性值(如phoneNumber)与对应对象列表的Map,其中value.size()>1表示该属性值重复
    Map<String, List<Person>> map = persons.stream()
                .collect(Collectors.groupingBy(Person::getPhoneNumber))
                .entrySet()
                .stream()
                .filter(entry -> entry.getValue().size() > 1)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        System.out.println(JSON.toJSONString(map));


    //提取重复属性值
    String duplicates =
                persons.stream()
                        .collect(Collectors.groupingBy(Person::getPhoneNumber, Collectors.toList()))
                        .entrySet()
                        .stream()
                        .filter(en -> en.getValue().size() > 1)
                        .map(Map.Entry::getKey)
                        .collect(Collectors.joining(","));
        System.out.println(duplicates);
    //方式二、使用toMap计数过滤。结合Collectors.toMap统计出现次数:
    //直接返回重复的属性值列表
    List<String> duplicateValues = persons.stream()
                .collect(Collectors.toMap(
                        Person::getPhoneNumber,
                        e -> 1,
                        Integer::sum
                ))
                .entrySet()
                .stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        System.out.println(duplicateValues);
    //转为字符串形式:"1,2,3,4"的形式
    String dupNumbers = persons.stream()
                    .collect(Collectors.toMap(
                            Person::getPhoneNumber,
                            e -> 1,
                            Integer::sum
                    ))
                    .entrySet()
                    .stream()
                    .filter(entry -> entry.getValue() > 1)
                    .map(Map.Entry::getKey)
                    .collect(Collectors.joining(","));

    //根据特定属性去重。若需基于属性去重而非提取重复值,可用:
    //通过TreeSet按phoneNumber去重
    List<Person> distinct = persons.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(
                                () -> new TreeSet<>(Comparator.comparing(Person::getPhoneNumber))
                        ),
                        ArrayList::new
                ));
        System.out.println(distinct);


    @Data
    public static class Person {
        private String name;
        private int age;
        private String phoneNumber;

        public Person(String name, int age, String phoneNumber) {
            this.name = name;
            this.age = age;
            this.phoneNumber = phoneNumber;
        }

    }
    

}

注意事项

  1. 对象需正确实现equals()hashCode()方法,否则分组可能失效5;
  2. 并行流处理时需注意线程安全问题9;
  3. 复杂对象建议使用Comparator.comparing()指定比较逻辑。
相关推荐
Leo July18 小时前
【Java】Spring Security 6.x 全解析:从基础认证到企业级权限架构
java·spring·架构
星火开发设计18 小时前
C++ 数组:一维数组的定义、遍历与常见操作
java·开发语言·数据结构·c++·学习·数组·知识
码道功成18 小时前
Pycham及IntelliJ Idea常用插件
java·ide·intellij-idea
消失的旧时光-194319 小时前
第四篇(实战): 订单表索引设计实战:从慢 SQL 到毫秒级
java·数据库·sql
それども19 小时前
@ModelAttribute vs @RequestBody
java
雨中飘荡的记忆20 小时前
深度详解Spring Context
java·spring
Tao____20 小时前
JAVA开源物联网平台
java·物联网·mqtt·开源·ruoyi
yqd66620 小时前
SpringSecurity的使用
java·spring
仙俊红20 小时前
Java Map 家族核心解析
java·开发语言
一嘴一个橘子21 小时前
springMvc 接收参数、cookie、header
java