当前位置: 代码网 > it编程>编程语言>Java > Java根据指定字段实现对对象进行去重的五种方法

Java根据指定字段实现对对象进行去重的五种方法

2025年07月24日 Java 我要评论
引入问题首先,我自定义了一个名为 person 的 java 类:public class person { private string name; private int age;

引入问题

首先,我自定义了一个名为 person 的 java 类:

public class person {
    private string name;
    private int age;

    public person(string name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @override
    public int hashcode() {
        return super.hashcode();
    }

    @override
    public boolean equals(object obj) {
        return super.equals(obj);
    }

    @override
    public string tostring() {
        return "person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

person 类中有两个属性:nameage 和一个全参构造方法:

  • name 是一个字符串类型的变量,用于表示人的姓名;age 是一个整数类型的变量,用于表示人的年龄。
  • 构造方法用于创建 person 类的对象。

并且重写了三个方法:hashcode()equals()tostring()

  • hashcode() 方法返回对象的哈希码,此处直接调用了父类 objecthashcode() 方法。
  • equals() 方法用于比较对象是否相等,此处直接调用了父类 objectequals() 方法。
  • tostring() 方法返回一个描述该对象内容的字符串,格式为 "person{name='姓名', age=年龄}"

最终,我们需要根据 person 类的 name 字段对目标集合进行去重:

public static void main(string[] args) {
    list<person> persons = new arraylist<>();
    persons.add(new person("tom", 20));
    persons.add(new person("jerry", 18));
    persons.add(new person("tom", 22));
    persons.add(new person("jim", 23));
    persons.add(new person("tom", 22));

    persons.foreach(system.out::println);
}

方法一:使用 hashset 数据结构

根据 java 对象某个字段进行去重,可以使用 hashset 数据结构。hashset 内部实现了哈希表,能够快速判断元素是否已存在,从而实现去重。

tips: hashset 是如何实现元素去重的,或者说如何判断元素是否重复?

在 java 中,hashset 是一种基于哈希表实现的集合类,它内部维护了一个存储元素的哈希表。hashset 通过元素的哈希码(hashcode)来判断元素是否重复的。

当我们向 hashset 中添加元素时,hashset 会首先计算该元素的哈希码,并根据哈希码将元素放入对应的桶中。如果该桶中已经有了相同哈希码的元素,则会调用元素的 equals() 方法,比较元素是否相等。如果相等,则认为该元素已经存在于 hashset 中,不进行重复添加;否则将该元素添加到集合中。

如果我们通过 hashset 进行去重,就需要正确地实现 hashcode() 和 equals() 方法。hashcode() 方法应该返回与元素属性相关的哈希码,而 equals() 方法应该根据元素属性判断元素是否相等。只有这样才能保证在 hashset 中正确地去重和查找元素。

使用 hashset 去重的具体步骤如下:

  1. 重写对象的 equalshashcode 方法。在这两个方法中,分别比较对象的指定字段,并返回相应的哈希值。
  2. 创建一个 hashset 对象,并将所有要去重的对象添加到该 hashset 中。
  3. 遍历该 hashset,处理去重后的结果。

重写 person 类的 equalshashcode 方法,用于比较指定字段:

public class person {
    
    ......
        
	// 重写 hashcode 方法
    @override
    public int hashcode() {
        // 哈希值只与 name 字段有关
        return name.hashcode(); 
    }
    
    // 重写 equals 方法
    @override
    public boolean equals(object o) {
        if (this == o) return true;
        if (o == null || getclass() != o.getclass()) return false;

        person person = (person) o;

        // 比较 name 字段
        return name.equals(person.name); 
    }
}

在重写的 equals() 方法中,首先使用 this == o 来判断两个对象是否为同一个对象(即内存地址是否相同),如果是,则直接返回 true。如果不是同一个对象,则继续比较其他属性。

接着,使用 o == null 判断传入的参数是否为 null,如果是 null,则两个对象肯定不相等,直接返回 false。然后使用 getclass() 方法来获取传入对象的类,判断其是否与当前对象的类相同,如果不同,则两个对象肯定不相等,直接返回 false

最后,将参数对象强制转换成 person 类型,并比较两个对象的 name 属性是否相等。如果相等,则认为两个对象相等,返回 true,否则返回 false

同时重写 hashcode() 方法,以确保两个对象相等时它们的哈希码也相等。

使用 hashset 去重:

public static void main(string[] args) {
    
	......
        
    hashset<person> personhashset = new hashset<>(persons);
    personhashset.foreach(system.out::println);
}

去重结果为:

person{name='tom', age=20}
person{name='jerry', age=18}
person{name='jim', age=23}

方法二:使用 java 8 的 stream api 的 distinct() 去重

java 8 增加的 stream api 提供了 distinct() 方法去重。

stream 流的 distinct() 方法是基于对象的 equals() 方法来判断对象是否相等,因此我们需要重写 person 类的 equals() 方法:

public class person {
    
    ......
    
    // 重写 equals 方法
    @override
    public boolean equals(object o) {
        if (this == o) return true;
        if (o == null || getclass() != o.getclass()) return false;

        person person = (person) o;

        // 比较 name 字段
        return name.equals(person.name); 
    }
}

之后调用 stream() 方法将列表转换为流,并且使用 distinct() 方法基于 name 字段进行去重:

list<person> collect = persons.stream()
                .distinct()
                .collect(collectors.tolist());

最后打印去重后的 person 集合:

person{name='tom', age=20}
person{name='jerry', age=18}
person{name='jim', age=23}

方法三:使用 map 数据结构

java 中的 map 是一种用于存储键值对的集合。我们可以利用 map 中的键唯一的特性实现去重。

我们只需要遍历 list 中的 person 对象,将 name 作为 key,person 对象作为 value 存入 map 中,这样就可以去除重复的 name 对应的 person 对象:

public static void main(string[] args) {

    ......

    map<string, person> map = new hashmap<>();
    for (person person : persons) {
        map.put(person.getname(), person);
    }
}

去重结果如下:

person{name='tom', age=22}
person{name='jerry', age=18}
person{name='jim', age=23}

方法四:使用 collectors.tomap() 方法

collectors.tomap()是 java 8 中的一个收集器(collector),它可以将 stream 中的元素收集到一个 map 中,其中每个元素都是一个键值对。该方法有多个重载形式:

  • tomap(function<? super t, ? extends k> keymapper, function<? super t, ? extends u> valuemapper)

将 stream 中的元素转换为键值对,并存储到一个map中。其中,keymapper用于指定如何从元素中提取键,valuemapper用于指定如何从元素中提取值。

如果存在重复的键,则会抛出illegalstateexception异常。

  • tomap(function<? super t, ? extends k> keymapper, function<? super t, ? extends u> valuemapper, binaryoperator<u> mergefunction)

与第一种形式类似,但当存在重复的键时,会使用mergefunction函数来处理冲突。例如,可以使用mergefunction来选择较小或较大的值,或将两个值合并成一个新值。

  • tomap(function<? super t, ? extends k> keymapper, function<? super t, ? extends u> valuemapper, binaryoperator<u> mergefunction, supplier<m> mapsupplier)

与第二种形式类似,但允许指定用于创建 map 的具体实现类。

使用第二种重载形式将包含person对象的list转换为一个以person对象的姓名作为键的map

public static void main(string[] args) {

    ......

   map<string, person> collect = persons.stream()
        .collect(collectors.tomap(person::getname, p -> p, (p1, p2) -> p1));
}
  • person::getname:函数式接口function类型的方法引用,用于将person对象的姓名作为键。
  • person -> person:lambda 表达式,用于将person对象本身作为值。
  • (p1, p2) -> p1:lambda 表达式,用于处理当存在重复键时的情况。此处选择保留第一个键对应的值,而忽略第二个键对应的值。

去重结果如下:

person{name='tom', age=20}
person{name='jerry', age=18}
person{name='jim', age=23}

方法五:使用 collectors.collectingandthen() 方法

collectors.collectingandthen()是 java 8 中的一个收集器(collector)方法,它允许在收集元素后应用一个最终转换函数。在使用collectingandthen()时,先通过一个初始的收集器将元素收集起来,然后再应用一个最终转换函数对收集结果进行处理。

以下是collectingandthen()方法的常用重载形式:

collectingandthen(collector<t, a, r> downstream, function<r, rr> finisher)

  • downstream:初始的收集器,用于将元素收集起来并生成一个中间结果。
  • finisher:最终转换函数,用于对中间结果进行处理,并返回最终结果。

使用collectingandthen()方法实现去重并返回去重后的结果集:

public static void main(string[] args) {

    ......

    arraylist<person> collect = persons.stream()
        .collect(collectors.collectingandthen(
            collectors.tomap(person::getname, person -> person, (p1, p2) -> p1),
            map -> new arraylist<>(map.values())
        ));
}
  • 使用collectors.tomap()persons流中的元素转换为一个以 name 作为键的map
  • 通过 map -> new arraylist<>(map.values())map的值部分提取出来,并使用arraylist的构造函数将其包装为一个新的arraylist<person>对象。最终得到的arraylist<person>对象即为去重后的结果集。

输出去重后的结果:

person{name='tom', age=20}
person{name='jerry', age=18}
person{name='jim', age=23}

以上就是java根据指定字段实现对对象进行去重的五种方法的详细内容,更多关于java指定字段对对象去重的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com