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()指定比较逻辑。
相关推荐
一直不明飞行1 小时前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
REDcker1 小时前
有限状态机与状态模式详解 FSM建模Java状态模式与C++表驱动模板实践
java·c++·状态模式
你的保护色2 小时前
【无标题】
java·服务器·网络
basketball6162 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
淘矿人2 小时前
Claude辅助DevOps实践
java·大数据·运维·人工智能·算法·bug·devops
小江的记录本3 小时前
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·mysql·spring·面试·职场和发展
来恩10033 小时前
请求转发与响应重定向的使用
java
@杰克成3 小时前
Java学习30
java·开发语言·学习
次元工程师!3 小时前
LangFlow开发(三)—Bundles组件架构设计(3W+字详细讲解)
java·前端·python·低代码·langflow
oddsand15 小时前
Redis网络模型
java·数据库·redis