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()指定比较逻辑。
相关推荐
深色風信子10 小时前
SpringBoot 集成 LangChain4j 本地调用 Ollama
java·spring boot·spring·ollama·langchain4j
卷心菜的学习路10 小时前
《计算》第九十章读书笔记
java·读书笔记·编程思维
开始学AI10 小时前
【Docker技术】docker-compose.yml与Dockerfile解析
java·docker·eureka
写代码的小阿帆13 小时前
Java体系总结——从基础语法到微服务
java·微服务·学习方法
SUPER526615 小时前
FastApi项目启动失败 got an unexpected keyword argument ‘loop_factory‘
java·服务器·前端
咕噜咕噜啦啦16 小时前
Eclipse集成开发环境的使用
java·ide·eclipse
光军oi19 小时前
全栈开发杂谈————关于websocket若干问题的大讨论
java·websocket·apache
weixin_4196583119 小时前
Spring 的统一功能
java·后端·spring
小许学java19 小时前
Spring AI-流式编程
java·后端·spring·sse·spring ai