前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Java中的对象去重工具类——灵活、高效的去重解决方案

Java中的对象去重工具类——灵活、高效的去重解决方案

作者头像
訾博ZiBo
发布2025-01-24 11:26:26
发布2025-01-24 11:26:26
5300
代码可运行
举报
运行总次数:0
代码可运行

Java中的对象去重工具类——灵活、高效的去重解决方案

完整代码
代码语言:javascript
代码运行次数:0
复制
package com.zibo.utils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 对象去重工具类
 * 提供了基于对象字段的灵活去重功能
 *
 * @author zibo
 * @date 2024/01/13
 */
public class DeduplicationUtils {

    private DeduplicationUtils() {
    }

    /**
     * 根据对象的一个或多个字段进行去重
     * 默认不保持原有列表顺序
     * -
     * 使用示例:
     * List<User> users = Arrays.asList(
     * new User("张三", 20),
     * new User("李四", 25),
     * new User("张三", 20)
     * );
     * // 根据name和age去重
     * List<User> unique = deduplicate(users, User::getName, User::getAge);
     *
     * @param list          要进行去重的列表
     * @param keyExtractors 用于提取去重关键字段的函数集合,可以是对象的任意字段的getter方法引用
     * @param <T>           对象类型
     * @return 去重后的新列表
     */
    @SafeVarargs
    public static <T> List<T> deduplicate(List<T> list, Function<? super T, ?>... keyExtractors) {
        return deduplicate(list, false, keyExtractors);
    }

    /**
     * 根据对象的一个或多个字段进行去重,可选择是否保持原有列表顺序
     * -
     * 使用示例:
     * List<User> users = Arrays.asList(
     * new User("张三", 20),
     * new User("李四", 25),
     * new User("张三", 20)
     * );
     * // 根据name去重,并保持原有顺序
     * List<User> unique = deduplicate(users, true, User::getName);
     *
     * @param list          要进行去重的列表
     * @param maintainOrder 是否保持原有列表顺序,true表示保持原顺序,false则不保证顺序
     * @param keyExtractors 用于提取去重关键字段的函数集合,可以是对象的任意字段的getter方法引用
     * @param <T>           对象类型
     * @return 去重后的新列表
     */
    @SafeVarargs
    public static <T> List<T> deduplicate(List<T> list, boolean maintainOrder, Function<? super T, ?>... keyExtractors) {
        // 空列表处理
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }

        // 如果没有指定去重字段,则使用对象本身的equals和hashCode方法进行去重
        if (keyExtractors == null || keyExtractors.length == 0) {
            if (maintainOrder) {
                // 使用Stream的distinct方法保持顺序去重
                return list.stream().distinct().collect(Collectors.toList());
            } else {
                // 使用HashSet去重(不保证顺序)
                Set<T> set = new HashSet<>(list);
                return new ArrayList<>(set);
            }
        }

        // 使用LinkedHashMap或ConcurrentHashMap进行去重,通过自定义key实现多字段组合去重
        if (maintainOrder) {
            // 使用LinkedHashMap保持原有顺序
            return list.stream()
                    .collect(Collectors.collectingAndThen(
                            Collectors.toMap(
                                    t -> generateKey(t, keyExtractors),  // 生成组合key
                                    Function.identity(),                  // 值为对象本身
                                    (t1, t2) -> t1,                      // 遇到重复时保留第一个
                                    LinkedHashMap::new                    // 使用LinkedHashMap保持顺序
                            ),
                            map -> new ArrayList<>(map.values())
                    ));
        } else {
            // 使用HashMap
            return list.stream()
                    .collect(Collectors.collectingAndThen(
                            Collectors.toMap(
                                    t -> generateKey(t, keyExtractors),  // 生成组合key
                                    Function.identity(),                  // 值为对象本身
                                    (t1, t2) -> t1,                      // 遇到重复时保留第一个
                                    HashMap::new                         // 使用HashMap即可
                            ),
                            map -> new ArrayList<>(map.values())
                    ));
        }
    }

    /**
     * 根据提供的字段提取器生成组合key
     * 将多个字段的值组合成一个List作为去重的key
     *
     * @param t             对象
     * @param keyExtractors 字段提取器数组
     * @param <T>           对象类型
     * @return 组合后的key列表
     */
    private static <T> List<Object> generateKey(T t, Function<? super T, ?>[] keyExtractors) {
        return Arrays.stream(keyExtractors)
                .map(extractor -> extractor.apply(t))
                .collect(Collectors.toList());
    }
}
引言

在日常开发中,我们经常会遇到需要对对象列表进行去重的需求。比如,从数据库中查询出一批用户数据,但其中可能存在重复记录,我们需要根据某些字段(如姓名、年龄等)来去除重复项。今天,我将分享一个非常实用的Java工具类——DeduplicationUtils,它可以帮助我们轻松实现基于对象字段的灵活去重。

工具类介绍

DeduplicationUtils 是一个专门用于对象去重的工具类,它提供了基于对象字段的灵活去重功能。通过这个工具类,我们可以根据一个或多个字段对对象列表进行去重,并且可以选择是否保持原有列表的顺序。

核心功能
  1. 基于字段去重:可以根据对象的一个或多个字段进行去重。
  2. 保持顺序:可以选择是否保持原有列表的顺序。
  3. 灵活使用:支持任意对象的字段去重,只需传入对应的字段提取器(如User::getName)。
使用示例

假设我们有一个User类,包含nameage两个字段:

代码语言:javascript
代码运行次数:0
复制
public class User {
    private String name;
    private int age;

    // 构造方法、getter和setter省略
}

现在,我们有一个User对象的列表,其中包含重复项:

代码语言:javascript
代码运行次数:0
复制
List<User> users = Arrays.asList(
    new User("张三", 20),
    new User("李四", 25),
    new User("张三", 20)
);

我们可以使用DeduplicationUtils来根据nameage字段进行去重:

代码语言:javascript
代码运行次数:0
复制
List<User> uniqueUsers = DeduplicationUtils.deduplicate(users, User::getName, User::getAge);

如果我们希望保持原有列表的顺序,可以这样调用:

代码语言:javascript
代码运行次数:0
复制
List<User> uniqueUsers = DeduplicationUtils.deduplicate(users, true, User::getName, User::getAge);
实现原理

DeduplicationUtils的核心逻辑是通过Stream API和Collectors.toMap方法来实现去重。具体步骤如下:

  1. 生成组合Key:根据传入的字段提取器,生成一个组合Key(即多个字段的值组成的列表)。
  2. 去重逻辑:使用Collectors.toMap方法,将对象列表转换为一个Map,其中Key是生成的组合Key,Value是对象本身。如果遇到重复的Key,则保留第一个对象。
  3. 保持顺序:如果选择保持顺序,则使用LinkedHashMap来存储结果;否则使用HashMap
代码解析

以下是DeduplicationUtils的核心代码:

代码语言:javascript
代码运行次数:0
复制
public static <T> List<T> deduplicate(List<T> list, boolean maintainOrder, Function<? super T, ?>... keyExtractors) {
    if (list == null || list.isEmpty()) {
        return new ArrayList<>();
    }

    if (keyExtractors == null || keyExtractors.length == 0) {
        if (maintainOrder) {
            return list.stream().distinct().collect(Collectors.toList());
        } else {
            Set<T> set = new HashSet<>(list);
            return new ArrayList<>(set);
        }
    }

    if (maintainOrder) {
        return list.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toMap(
                                t -> generateKey(t, keyExtractors),
                                Function.identity(),
                                (t1, t2) -> t1,
                                LinkedHashMap::new
                        ),
                        map -> new ArrayList<>(map.values())
                ));
    } else {
        return list.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toMap(
                                t -> generateKey(t, keyExtractors),
                                Function.identity(),
                                (t1, t2) -> t1,
                                HashMap::new
                        ),
                        map -> new ArrayList<>(map.values())
                ));
    }
}

private static <T> List<Object> generateKey(T t, Function<? super T, ?>[] keyExtractors) {
    return Arrays.stream(keyExtractors)
            .map(extractor -> extractor.apply(t))
            .collect(Collectors.toList());
}
总结

DeduplicationUtils是一个非常实用的工具类,它可以帮助我们轻松实现基于对象字段的去重功能。无论是简单的单字段去重,还是复杂的多字段组合去重,它都能胜任。此外,它还提供了保持顺序的选项,满足了不同场景下的需求。

如果你在项目中遇到类似的需求,不妨试试这个工具类,相信它会为你节省不少时间和精力。

参考

希望这篇博客对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言讨论。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java中的对象去重工具类——灵活、高效的去重解决方案
    • 完整代码
    • 引言
    • 工具类介绍
    • 核心功能
    • 使用示例
    • 实现原理
    • 代码解析
    • 总结
    • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档