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()指定比较逻辑。
相关推荐
没有bug.的程序员1 天前
服务安全:内部服务如何防止“裸奔”?
java·网络安全·云原生安全·服务安全·零信任架构·微服务安全·内部鉴权
一线大码1 天前
SpringBoot 3 和 4 的版本新特性和升级要点
java·spring boot·后端
weixin_440730501 天前
java数组整理笔记
java·开发语言·笔记
weixin_425023001 天前
Spring Boot 实用核心技巧汇总:日期格式化、线程管控、MCP服务、AOP进阶等
java·spring boot·后端
一线大码1 天前
Java 8-25 各个版本新特性总结
java·后端
2501_906150561 天前
私有部署问卷系统操作实战记录-DWSurvey
java·运维·服务器·spring·开源
better_liang1 天前
每日Java面试场景题知识点之-TCP/IP协议栈与Socket编程
java·tcp/ip·计算机网络·网络编程·socket·面试题
niucloud-admin1 天前
java服务端——controller控制器
java·开发语言
To Be Clean Coder1 天前
【Spring源码】通过 Bean 工厂获取 Bean 的过程
java·后端·spring
Fortunate Chen1 天前
类与对象(下)
java·javascript·jvm