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()指定比较逻辑。
相关推荐
咖啡八杯2 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
优橙教育2 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
糖果店的幽灵2 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
腻害兔4 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
碎光拾影4 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Miao121315 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
腻害兔5 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程
CRMEB系统商城6 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
keyipatience7 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu
weixin_408099678 小时前
2026 图片去水印 API 接口完全指南:一键去除图片水印(附 Python/Java/PHP/C# 示例)
java·python·php·图片处理·api调用·图片去水印·石榴智能