最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java根據(jù)指定字段實(shí)現(xiàn)對(duì)對(duì)象進(jìn)行去重的五種方法

 更新時(shí)間:2025年07月24日 09:32:51   作者:@趙士杰  
在Java編程中,去重是一個(gè)常見的需求,尤其是當(dāng)我們處理大量數(shù)據(jù)時(shí),然而,去重的方式在于需求的具體情況,尤其是我們想要基于哪些字段進(jìn)行去重,本文將介紹如何在Java中實(shí)現(xiàn)指定字段的去重,并通過(guò)代碼示例來(lái)幫助讀者理解,需要的朋友可以參考下

引入問(wèn)題

首先,我自定義了一個(gè)名為 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 類中有兩個(gè)屬性:nameage 和一個(gè)全參構(gòu)造方法:

  • name 是一個(gè)字符串類型的變量,用于表示人的姓名;age 是一個(gè)整數(shù)類型的變量,用于表示人的年齡。
  • 構(gòu)造方法用于創(chuàng)建 Person 類的對(duì)象。

并且重寫了三個(gè)方法:hashCode()、equals()toString()

  • hashCode() 方法返回對(duì)象的哈希碼,此處直接調(diào)用了父類 ObjecthashCode() 方法。
  • equals() 方法用于比較對(duì)象是否相等,此處直接調(diào)用了父類 Objectequals() 方法。
  • toString() 方法返回一個(gè)描述該對(duì)象內(nèi)容的字符串,格式為 "Person{name='姓名', age=年齡}"。

最終,我們需要根據(jù) Person 類的 name 字段對(duì)目標(biāo)集合進(jìn)行去重:

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 數(shù)據(jù)結(jié)構(gòu)

根據(jù) Java 對(duì)象某個(gè)字段進(jìn)行去重,可以使用 HashSet 數(shù)據(jù)結(jié)構(gòu)。HashSet 內(nèi)部實(shí)現(xiàn)了哈希表,能夠快速判斷元素是否已存在,從而實(shí)現(xiàn)去重。

Tips: HashSet 是如何實(shí)現(xiàn)元素去重的,或者說(shuō)如何判斷元素是否重復(fù)?

在 Java 中,HashSet 是一種基于哈希表實(shí)現(xiàn)的集合類,它內(nèi)部維護(hù)了一個(gè)存儲(chǔ)元素的哈希表。HashSet 通過(guò)元素的哈希碼(hashcode)來(lái)判斷元素是否重復(fù)的。

當(dāng)我們向 HashSet 中添加元素時(shí),HashSet 會(huì)首先計(jì)算該元素的哈希碼,并根據(jù)哈希碼將元素放入對(duì)應(yīng)的桶中。如果該桶中已經(jīng)有了相同哈希碼的元素,則會(huì)調(diào)用元素的 equals() 方法,比較元素是否相等。如果相等,則認(rèn)為該元素已經(jīng)存在于 HashSet 中,不進(jìn)行重復(fù)添加;否則將該元素添加到集合中。

如果我們通過(guò) HashSet 進(jìn)行去重,就需要正確地實(shí)現(xiàn) hashCode() 和 equals() 方法。hashCode() 方法應(yīng)該返回與元素屬性相關(guān)的哈希碼,而 equals() 方法應(yīng)該根據(jù)元素屬性判斷元素是否相等。只有這樣才能保證在 HashSet 中正確地去重和查找元素。

使用 HashSet 去重的具體步驟如下:

  1. 重寫對(duì)象的 equalshashCode 方法。在這兩個(gè)方法中,分別比較對(duì)象的指定字段,并返回相應(yīng)的哈希值。
  2. 創(chuàng)建一個(gè) HashSet 對(duì)象,并將所有要去重的對(duì)象添加到該 HashSet 中。
  3. 遍歷該 HashSet,處理去重后的結(jié)果。

重寫 Person 類的 equalshashCode 方法,用于比較指定字段:

public class Person {
    
    ......
        
	// 重寫 hashCode 方法
    @Override
    public int hashCode() {
        // 哈希值只與 name 字段有關(guān)
        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 來(lái)判斷兩個(gè)對(duì)象是否為同一個(gè)對(duì)象(即內(nèi)存地址是否相同),如果是,則直接返回 true。如果不是同一個(gè)對(duì)象,則繼續(xù)比較其他屬性。

接著,使用 o == null 判斷傳入的參數(shù)是否為 null,如果是 null,則兩個(gè)對(duì)象肯定不相等,直接返回 false。然后使用 getClass() 方法來(lái)獲取傳入對(duì)象的類,判斷其是否與當(dāng)前對(duì)象的類相同,如果不同,則兩個(gè)對(duì)象肯定不相等,直接返回 false。

最后,將參數(shù)對(duì)象強(qiáng)制轉(zhuǎn)換成 Person 類型,并比較兩個(gè)對(duì)象的 name 屬性是否相等。如果相等,則認(rèn)為兩個(gè)對(duì)象相等,返回 true,否則返回 false

同時(shí)重寫 hashCode() 方法,以確保兩個(gè)對(duì)象相等時(shí)它們的哈希碼也相等。

使用 HashSet 去重:

public static void main(String[] args) {
    
	......
        
    HashSet<Person> personHashSet = new HashSet<>(persons);
    personHashSet.forEach(System.out::println);
}

去重結(jié)果為:

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() 方法是基于對(duì)象的 equals() 方法來(lái)判斷對(duì)象是否相等,因此我們需要重寫 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); 
    }
}

之后調(diào)用 stream() 方法將列表轉(zhuǎn)換為流,并且使用 distinct() 方法基于 name 字段進(jìn)行去重:

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 數(shù)據(jù)結(jié)構(gòu)

Java 中的 Map 是一種用于存儲(chǔ)鍵值對(duì)的集合。我們可以利用 Map 中的鍵唯一的特性實(shí)現(xiàn)去重。

我們只需要遍歷 List 中的 Person 對(duì)象,將 name 作為 key,Person 對(duì)象作為 value 存入 Map 中,這樣就可以去除重復(fù)的 name 對(duì)應(yīng)的 Person 對(duì)象:

public static void main(String[] args) {

    ......

    Map<String, Person> map = new HashMap<>();
    for (Person person : persons) {
        map.put(person.getName(), person);
    }
}

去重結(jié)果如下:

Person{name='Tom', age=22}
Person{name='Jerry', age=18}
Person{name='Jim', age=23}

方法四:使用 Collectors.toMap() 方法

Collectors.toMap()是 Java 8 中的一個(gè)收集器(Collector),它可以將 Stream 中的元素收集到一個(gè) Map 中,其中每個(gè)元素都是一個(gè)鍵值對(duì)。該方法有多個(gè)重載形式:

  • toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)

將 Stream 中的元素轉(zhuǎn)換為鍵值對(duì),并存儲(chǔ)到一個(gè)Map中。其中,keyMapper用于指定如何從元素中提取鍵,valueMapper用于指定如何從元素中提取值。

如果存在重復(fù)的鍵,則會(huì)拋出IllegalStateException異常。

  • toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction)

與第一種形式類似,但當(dāng)存在重復(fù)的鍵時(shí),會(huì)使用mergeFunction函數(shù)來(lái)處理沖突。例如,可以使用mergeFunction來(lái)選擇較小或較大的值,或?qū)蓚€(gè)值合并成一個(gè)新值。

  • toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)

與第二種形式類似,但允許指定用于創(chuàng)建 Map 的具體實(shí)現(xiàn)類。

使用第二種重載形式將包含Person對(duì)象的List轉(zhuǎn)換為一個(gè)以Person對(duì)象的姓名作為鍵的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:函數(shù)式接口Function類型的方法引用,用于將Person對(duì)象的姓名作為鍵。
  • person -> person:Lambda 表達(dá)式,用于將Person對(duì)象本身作為值。
  • (p1, p2) -> p1:Lambda 表達(dá)式,用于處理當(dāng)存在重復(fù)鍵時(shí)的情況。此處選擇保留第一個(gè)鍵對(duì)應(yīng)的值,而忽略第二個(gè)鍵對(duì)應(yīng)的值。

去重結(jié)果如下:

Person{name='Tom', age=20}
Person{name='Jerry', age=18}
Person{name='Jim', age=23}

方法五:使用 Collectors.collectingAndThen() 方法

Collectors.collectingAndThen()是 Java 8 中的一個(gè)收集器(Collector)方法,它允許在收集元素后應(yīng)用一個(gè)最終轉(zhuǎn)換函數(shù)。在使用collectingAndThen()時(shí),先通過(guò)一個(gè)初始的收集器將元素收集起來(lái),然后再應(yīng)用一個(gè)最終轉(zhuǎn)換函數(shù)對(duì)收集結(jié)果進(jìn)行處理。

以下是collectingAndThen()方法的常用重載形式:

collectingAndThen(Collector<T, A, R> downstream, Function<R, RR> finisher)

  • downstream:初始的收集器,用于將元素收集起來(lái)并生成一個(gè)中間結(jié)果。
  • finisher:最終轉(zhuǎn)換函數(shù),用于對(duì)中間結(jié)果進(jìn)行處理,并返回最終結(jié)果。

使用collectingAndThen()方法實(shí)現(xiàn)去重并返回去重后的結(jié)果集:

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流中的元素轉(zhuǎn)換為一個(gè)以 name 作為鍵的Map。
  • 通過(guò) map -> new ArrayList<>(map.values())Map的值部分提取出來(lái),并使用ArrayList的構(gòu)造函數(shù)將其包裝為一個(gè)新的ArrayList<Person>對(duì)象。最終得到的ArrayList<Person>對(duì)象即為去重后的結(jié)果集。

輸出去重后的結(jié)果:

Person{name='Tom', age=20}
Person{name='Jerry', age=18}
Person{name='Jim', age=23}

以上就是Java根據(jù)指定字段實(shí)現(xiàn)對(duì)對(duì)象進(jìn)行去重的五種方法的詳細(xì)內(nèi)容,更多關(guān)于Java指定字段對(duì)對(duì)象去重的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Mybatis延遲加載的實(shí)現(xiàn)方式

    Mybatis延遲加載的實(shí)現(xiàn)方式

    這篇文章主要介紹了Mybatis延遲加載的實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Mybatis與Jpa的區(qū)別和性能對(duì)比總結(jié)

    Mybatis與Jpa的區(qū)別和性能對(duì)比總結(jié)

    mybatis和jpa兩個(gè)持久層框架,從底層到用法都不同,但是實(shí)現(xiàn)的功能是一樣的,所以說(shuō)一直以來(lái)頗有爭(zhēng)議,所以下面這篇文章主要給大家介紹了關(guān)于Mybatis與Jpa的區(qū)別和性能對(duì)比的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • Java實(shí)現(xiàn)復(fù)原IP地址的方法

    Java實(shí)現(xiàn)復(fù)原IP地址的方法

    這篇文章主要介紹了Java實(shí)現(xiàn)復(fù)原IP地址的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • MyBatis3傳遞多個(gè)參數(shù)(Multiple Parameters)

    MyBatis3傳遞多個(gè)參數(shù)(Multiple Parameters)

    這篇文章主要介紹了MyBatis3傳遞多個(gè)參數(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java基于NIO實(shí)現(xiàn)群聊系統(tǒng)

    Java基于NIO實(shí)現(xiàn)群聊系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java基于NIO實(shí)現(xiàn)群聊系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • AsyncHttpClient ListenableFuture源碼流程解讀

    AsyncHttpClient ListenableFuture源碼流程解讀

    這篇文章主要為大家介紹了AsyncHttpClient ListenableFuture源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Mybatis流式查詢并實(shí)現(xiàn)將結(jié)果分批寫入文件

    Mybatis流式查詢并實(shí)現(xiàn)將結(jié)果分批寫入文件

    這篇文章主要介紹了Mybatis流式查詢并實(shí)現(xiàn)將結(jié)果分批寫入文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • java實(shí)戰(zhàn)小技巧之優(yōu)雅的實(shí)現(xiàn)字符串拼接

    java實(shí)戰(zhàn)小技巧之優(yōu)雅的實(shí)現(xiàn)字符串拼接

    字符串拼接是我們?cè)贘ava代碼中比較經(jīng)常要做的事情,就是把多個(gè)字符串拼接到一起,這篇文章主要給大家介紹了關(guān)于java實(shí)戰(zhàn)小技巧之優(yōu)雅的實(shí)現(xiàn)字符串拼接的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • MyBatis-Plus中AutoGenerator的使用案例

    MyBatis-Plus中AutoGenerator的使用案例

    AutoGenerator是MyBatis-Plus的代碼生成器,通過(guò)?AutoGenerator?可以快速生成?Pojo、Mapper、?Mapper?XML、Service、Controller?等各個(gè)模塊的代碼,這篇文章主要介紹了MyBatis-Plus中AutoGenerator的詳細(xì)使用案例,需要的朋友可以參考下
    2023-05-05
  • Java實(shí)現(xiàn)多線程模擬龜兔賽跑

    Java實(shí)現(xiàn)多線程模擬龜兔賽跑

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)多線程模擬龜兔賽跑,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11

最新評(píng)論

云和县| 双峰县| 静安区| 开远市| 平顺县| 滁州市| 炉霍县| 丰顺县| 茶陵县| 沙田区| 延吉市| 留坝县| 青神县| 滕州市| 台南市| 神池县| 蒲城县| 道孚县| 临海市| 和平区| 万全县| 土默特左旗| 临清市| 儋州市| 张家港市| 绥滨县| 永泰县| 耿马| 石景山区| 迭部县| 红桥区| 乳山市| 屏东市| 洪湖市| 霍邱县| 九寨沟县| 盖州市| 汝城县| 宁都县| 渭南市| 大同县|