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

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

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

引入問題

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

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

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

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

最終,我們需要根據(jù) Person 類的 name 字段對目標(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 對象某個字段進(jìn)行去重,可以使用 HashSet 數(shù)據(jù)結(jié)構(gòu)。HashSet 內(nèi)部實現(xiàn)了哈希表,能夠快速判斷元素是否已存在,從而實現(xiàn)去重。

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

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

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

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

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

  1. 重寫對象的 equalshashCode 方法。在這兩個方法中,分別比較對象的指定字段,并返回相應(yīng)的哈希值。
  2. 創(chuàng)建一個 HashSet 對象,并將所有要去重的對象添加到該 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 來判斷兩個對象是否為同一個對象(即內(nèi)存地址是否相同),如果是,則直接返回 true。如果不是同一個對象,則繼續(xù)比較其他屬性。

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

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

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

使用 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() 方法是基于對象的 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); 
    }
}

之后調(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 是一種用于存儲鍵值對的集合。我們可以利用 Map 中的鍵唯一的特性實現(xiàn)去重。

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

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 中的一個收集器(Collector),它可以將 Stream 中的元素收集到一個 Map 中,其中每個元素都是一個鍵值對。該方法有多個重載形式:

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

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

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

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

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

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

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

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

去重結(jié)果如下:

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

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

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

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

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

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

使用collectingAndThen()方法實現(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)換為一個以 name 作為鍵的Map
  • 通過 map -> new ArrayList<>(map.values())Map的值部分提取出來,并使用ArrayList的構(gòu)造函數(shù)將其包裝為一個新的ArrayList<Person>對象。最終得到的ArrayList<Person>對象即為去重后的結(jié)果集。

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

    AsyncHttpClient ListenableFuture源碼流程解讀

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

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

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

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

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

    MyBatis-Plus中AutoGenerator的使用案例

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

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

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

最新評論

津南区| 孝义市| 贺兰县| 乐安县| 云南省| 大荔县| 阿巴嘎旗| 鸡泽县| 横峰县| 潜江市| 突泉县| 成武县| 丰镇市| 土默特左旗| 花莲县| 米泉市| 神木县| 景宁| 玉龙| 郧西县| 九龙城区| 汾阳市| 五指山市| 万山特区| 田东县| 双牌县| 威海市| 利辛县| 建德市| 德化县| 新河县| 油尖旺区| 武冈市| 莱西市| 崇信县| 汕尾市| 依安县| 神木县| 墨竹工卡县| 锦州市| 上饶县|