国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法

這篇具有很好參考價(jià)值的文章主要介紹了java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法

一、簡單去重

public class DistinctTest {
    /**
     * 沒有重寫 equals 方法
     */
    @Setter
    @Getter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public static class User {
        private String name;
        private Integer age;
    }

    /**
     * lombok(@Data) 重寫了 equals 方法 和 hashCode 方法
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class User2 {
        private String name;
        private Integer age;
    }

    @Test
    public void easyTest() {
        List<Integer> integers = Arrays.asList(1, 1, 2, 3, 4, 4, 5, 6, 77, 77);
        System.out.println("======== 數(shù)字去重 =========");
        System.out.print("原數(shù)字列表:");
        integers.forEach(x -> System.out.print(x + " "));
        System.out.println();
        System.out.print("去重后數(shù)字列表:");
        integers.stream().distinct().collect(Collectors.toList()).forEach(x -> System.out.print(x + " "));

        System.out.println();
        System.out.println();

        List<User> list = Lists.newArrayList();
        User three = new User("張三", 18);
        User three2 = new User("張三", 18);
        User three3 = new User("張三", 24);
        User four = new User("李四", 18);
        list.add(three);
        list.add(three);
        list.add(three2);
        list.add(three3);
        list.add(four);
        System.out.println("======== 沒有重寫equals方法的話,只能對(duì)相同對(duì)象(如:three)進(jìn)行去重,不能做到元素相同就可以去重) =========");
        // 沒有重寫 equals 方法時(shí),使用的是超類 Object 的 equals 方法
        // 等價(jià)于兩個(gè)對(duì)象 == 的比較,只能篩選同一個(gè)對(duì)象
        System.out.println("初始對(duì)象列表:");
        list.forEach(System.out::println);
        System.out.println("簡單去重后初始對(duì)象列表:");
        list.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);

        System.out.println();
        System.out.println();

        List<User2> list2 = Lists.newArrayList();
        User2 five = new User2("王五", 18);
        User2 five2 = new User2("王五", 18);
        User2 five3 = new User2("王五", 24);
        User2 two = new User2("二蛋", 18);
        list2.add(five);
        list2.add(five);
        list2.add(five2);
        list2.add(five3);
        list2.add(two);
        System.out.println("======== 重寫了equals方法的話,可以做到元素相同就可以去重) =========");
        // 所以如果只需要寫好 equals 方法 和 hashCode 方法 也能做到指定屬性的去重
        System.out.println("初始對(duì)象列表:");
        list2.forEach(System.out::println);
        System.out.println("簡單去重后初始對(duì)象列表:");
        list2.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);
    }
}

二、根據(jù)對(duì)象某個(gè)屬性去重

0、User對(duì)象

    /**
     * 沒有重寫 equals 方法
     */
    @Setter
    @Getter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public static class User {
        private String name;
        private Integer age;
    }

1、使用filter進(jìn)行去重

    @Test
    public void objectTest() {
        List<User> list = Arrays.asList(
                new User(null, 18),
                new User("張三", null),
                null,
                new User("張三", 24),
                new User("張三5", 24),
                new User("李四", 18)
        );
        System.out.println("初始對(duì)象列表:");
        list.forEach(System.out::println);
        System.out.println();
        System.out.println("======== 使用 filter ,根據(jù)特定屬性進(jìn)行過濾(重不重寫equals方法都不重要) =========");
        System.out.println("根據(jù)名字過濾后的對(duì)象列表:");
        // 第一個(gè) filter 是用于過濾 第二個(gè) filter 是用于去重
        List<User> collect = list.stream().filter(o -> o != null && o.getName() != null)
                .filter(distinctPredicate(User::getName)).collect(Collectors.toList());
        collect.forEach(System.out::println);
        System.out.println("根據(jù)年齡過濾后的對(duì)象列表:");
        List<User> collect1 = list.stream().filter(o -> o != null && o.getAge() != null)
                .filter(distinctPredicate(User::getAge)).collect(Collectors.toList());
        collect1.forEach(System.out::println);
    }

    /**
     * 列表對(duì)象去重
     */
    public <K, T> Predicate<K> distinctPredicate(Function<K, T> function) {
        // 因?yàn)閟tream流是多線程操作所以需要使用線程安全的ConcurrentHashMap
        ConcurrentHashMap<T, Boolean> map = new ConcurrentHashMap<>();
        return t -> null == map.putIfAbsent(function.apply(t), true);
    }
測試

java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法,java,java,windows,開發(fā)語言,后端,junit,jvm

①、疑惑

既然 filter 里面調(diào)用的是 distinctPredicate 方法,而該方法每次都 new 一個(gè)新的 map 對(duì)象,那么 map 就是新的,怎么能做到可以過濾呢

②、解惑

先看一下 filter 的部分實(shí)現(xiàn)邏輯,他使用了函數(shù)式接口 Predicate ,每次調(diào)用filter時(shí),會(huì)使用 predicate 對(duì)象的 test 方法,這個(gè)對(duì)象的test 方法就是 null == map.putIfAbsent(function.apply(t), true)

而 distinctPredicate 方法作用就是生成了一個(gè)線程安全的 Map 集合,和一個(gè) predicate 對(duì)象,且該對(duì)象的 test 方法為 null == map.putIfAbsent(function.apply(t), true)

之后 stream 流的 filter 方法每次都只會(huì)使用 predicate 對(duì)象的 test 方法,而該 test 方法中的 map 對(duì)象在該流中是唯一的,并不會(huì)重新初始化

    @Override
    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
        Objects.requireNonNull(predicate);
        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SIZED) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                    @Override
                    public void begin(long size) {
                        downstream.begin(-1);
                    }

                    @Override
                    public void accept(P_OUT u) {
                        if (predicate.test(u))
                            downstream.accept(u);
                    }
                };
            }
        };
    }

2、使用Collectors.toMap() 實(shí)現(xiàn)根據(jù)某一屬性去重(這個(gè)可以實(shí)現(xiàn)保留前一個(gè)還是后一個(gè))

要注意 Collectors.toMap(key,value) 中 value 不能為空,會(huì)報(bào)錯(cuò),key 可以為 null,但會(huì)被轉(zhuǎn)換為字符串的 “null”

    @Test
    public void objectTest() {
        List<User> list = Arrays.asList(
                new User(null, 18),
                new User("張三", null),
                null,
                new User("張三", 24),
                new User("張三5", 24),
                new User("李四", 18)
        );

        System.out.println("初始對(duì)象列表:");
        list.forEach(System.out::println);
        System.out.println();
        System.out.println("======== 使用 Collectors.toMap() 實(shí)現(xiàn)根據(jù)某一屬性去重 =========");
        System.out.println("根據(jù)名字過濾后的對(duì)象列表 寫法1:");
        // (v1, v2) -> v1 的意思 兩個(gè)名字一樣的話(key一樣),存前一個(gè) value 值
        Map<String, User> collect = list.stream().filter(Objects::nonNull).collect(Collectors.toMap(User::getName, o -> o, (v1, v2) -> v1));
        // o -> o 也可以寫為 Function.identity() ,兩個(gè)是一樣的,但后者可能比較優(yōu)雅,但閱讀性不高,如下
        // Map<String, User> collect = list.stream().filter(Objects::nonNull).collect(Collectors.toMap(User::getName, Function.identity(), (v1, v2) -> v1));
        List<User> list2 = new ArrayList<>(collect.values());
        list2.forEach(System.out::println);
        System.out.println("根據(jù)名字過濾后的對(duì)象列表 寫法2:");
        Map<String, User> map2 = list.stream().filter(o -> o != null && o.getName() != null)
                .collect(HashMap::new, (m, o) -> m.put(o.getName(), o), HashMap::putAll);
        list2 = new ArrayList<>(map2.values());
        list2.forEach(System.out::println);
        
        System.out.println("根據(jù)年齡過濾后的對(duì)象列表:");
        // (v1, k2) -> v2 的意思 兩個(gè)年齡一樣的話(key一樣),存后一個(gè) value 值
        Map<Integer, User> collect2 = list.stream().filter(Objects::nonNull).collect(Collectors.toMap(User::getAge, o -> o, (v1, v2) -> v2));
        list2 = new ArrayList<>(collect2.values());
        list2.forEach(System.out::println);

    }
測試

java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法,java,java,windows,開發(fā)語言,后端,junit,jvm

2.2、Collectors.toMap() 的變種 使用 Collectors.collectingAndThen()

Collectors.collectingAndThen() 函數(shù) 它可接受兩個(gè)參數(shù),第一個(gè)參數(shù)用于 reduce操作,而第二參數(shù)用于 map操作。

也就是,先把流中的所有元素傳遞給第一個(gè)參數(shù),然后把生成的集合傳遞給第二個(gè)參數(shù)來處理。


    @Test
    public void objectTest() {
        List<User> list = Arrays.asList(
                new User(null, 18),
                new User("張三", null),
                null,
                new User("張三", 24),
                new User("張三5", 24),
                new User("李四", 18)
        );
        System.out.println("初始對(duì)象列表:");
        list.forEach(System.out::println);
        System.out.println();
        System.out.println("======== 使用 Collectors.toMap() 實(shí)現(xiàn)根據(jù)某一屬性去重 =========");
        System.out.println("根據(jù)名字過濾后的對(duì)象列表:");
        ArrayList<User> collect1 = list.stream().filter(o -> o != null && o.getName() != null).collect(
                Collectors.collectingAndThen(Collectors.toMap(User::getName, o -> o, (k1, k2) -> k2), x-> new ArrayList<>(x.values())));
        collect1.forEach(System.out::println);
        System.out.println("======== 或者 ==========");
        List<User> collect = list.stream().filter(o -> o != null && o.getName() != null).collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList<User>::new));
        collect.forEach(System.out::println);
    }
測試

java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法,java,java,windows,開發(fā)語言,后端,junit,jvm

三、測試哪個(gè)方法比較快

    @Test
    public void objectTest() {
        List<User> list = new ArrayList<>(Arrays.asList(
                new User(null, 18),
                new User("張三", null),
                null,
                new User("張三", 24),
                new User("張三5", 24),
                new User("李四", 18)
        ));
        for (int i = 0; i < 100000; i++) {
            list.add(new User((Math.random() * 10) + "", (int) (Math.random() * 10)));
        }
        System.out.println("======== 測試速度 =========");
        long startTime = System.currentTimeMillis();
        List<User> list1 = list.stream().filter(o -> o != null && o.getName() != null)
                .filter(distinctPredicate(User::getName)).collect(Collectors.toList());
        long endTime = System.currentTimeMillis();
        System.out.println("filter 用時(shí) :" + (endTime - startTime));

        System.out.println();
        startTime = System.currentTimeMillis();
        Map<String, User> map1 = list.stream().filter(o -> o != null && o.getName() != null)
                .collect(Collectors.toMap(User::getName, o -> o, (v1, v2) -> v1));
        List<User> list2 = new ArrayList<>(map1.values());
        endTime = System.currentTimeMillis();
        System.out.println("map1 用時(shí) :" + (endTime - startTime));

        System.out.println();
        startTime = System.currentTimeMillis();
        ArrayList<User> list3 = list.stream().filter(o -> o != null && o.getName() != null).collect(
                Collectors.collectingAndThen(Collectors.toMap(User::getName, o -> o, (k1, k2) -> k2), x -> new ArrayList<>(x.values())));
        endTime = System.currentTimeMillis();
        System.out.println("map2 用時(shí) :" + (endTime - startTime));

        System.out.println();
        startTime = System.currentTimeMillis();
        List<User> list4 = list.stream().filter(o -> o != null && o.getName() != null).collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList<User>::new));
        endTime = System.currentTimeMillis();
        System.out.println("map3 用時(shí) :" + (endTime - startTime));

        System.out.println();
        startTime = System.currentTimeMillis();
        Map<String, User> map2 = list.stream().filter(o -> o != null && o.getName() != null)
                .collect(HashMap::new, (m, o) -> m.put(o.getName(), o), HashMap::putAll);
        List<User> list5 = new ArrayList<>(map2.values());
        endTime = System.currentTimeMillis();
        System.out.println("map4 用時(shí) :" + (endTime - startTime));
    }

測試:

java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法,java,java,windows,開發(fā)語言,后端,junit,jvm文章來源地址http://www.zghlxwxcb.cn/news/detail-807912.html

四、結(jié)論

1、去重最快:

	ArrayList<User> list3 = list.stream().filter(o -> o != null && o.getName() != null).collect(
                Collectors.collectingAndThen(Collectors.toMap(User::getName, o -> o, (k1, k2) -> k2), x -> new ArrayList<>(x.values())));
	// 或者
	Map<String, User> map2 = list.stream().filter(o -> o != null && o.getName() != null)
                .collect(HashMap::new, (m, o) -> m.put(o.getName(), o), HashMap::putAll);
	List<User> list5 = new ArrayList<>(map2.values());

2、其次

        Map<String, User> map1 = list.stream().filter(o -> o != null && o.getName() != null)
                .collect(Collectors.toMap(User::getName, o -> o, (v1, v2) -> v1));
        List<User> list2 = new ArrayList<>(map1.values());

		// distinctPredicate 是一個(gè)方法 本文中有 ,可以 ctrl + f 查找
        List<User> list1 = list.stream().filter(o -> o != null && o.getName() != null)
                .filter(distinctPredicate(User::getName)).collect(Collectors.toList());

3、最慢

	List<User> list4 = list.stream().filter(o -> o != null && o.getName() != null).collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList<User>::new));

到了這里,關(guān)于java8 列表通過 stream流 根據(jù)對(duì)象屬性去重的三種實(shí)現(xiàn)方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Java當(dāng)中List集合根據(jù)對(duì)象某個(gè)屬性進(jìn)行去重

    Java當(dāng)中List集合根據(jù)對(duì)象某個(gè)屬性進(jìn)行去重

    關(guān)于以下方法,直接可以在自己項(xiàng)目創(chuàng)建一個(gè)類,然后進(jìn)行測試使用,去重方式有很多種,文本末尾也提供了每個(gè)方法的運(yùn)行結(jié)果,供大家參考使用! 文章大量使用到了Java8當(dāng)中的Lambda表達(dá)式,以及stream流相關(guān)基礎(chǔ)知識(shí)。如果您用的不熟,沒關(guān)系,可以直接復(fù)制下面的方案然

    2024年02月16日
    瀏覽(95)
  • list根據(jù)對(duì)象中某個(gè)字段屬性去重Java流實(shí)現(xiàn)

    list根據(jù)對(duì)象中某個(gè)字段屬性去重Java流實(shí)現(xiàn)

    在Java的流(Stream)中,你可以使用distinct方法來實(shí)現(xiàn)根據(jù)對(duì)象中某個(gè)字段屬性去重的功能。要實(shí)現(xiàn)這個(gè)功能,你需要重寫對(duì)象的hashCode和equals方法,以確保相同字段屬性的對(duì)象被認(rèn)為是相等的。以下是一個(gè)示例代碼: 在上面的代碼中,YourObject是你自定義的對(duì)象類型,你需要根據(jù)

    2024年02月10日
    瀏覽(101)
  • 快速去重:使用Java根據(jù)對(duì)象某一屬性去除重復(fù)對(duì)象的實(shí)現(xiàn)指南

    ???? Java中的對(duì)象去重操作?跟著小編一起學(xué)習(xí)吧!?? 在處理對(duì)象集合時(shí),有時(shí)候我們需要根據(jù)對(duì)象的某個(gè)屬性進(jìn)行去重操作。Java給我們提供了多種方法來實(shí)現(xiàn)這個(gè)功能。今天,小編就來給大家介紹一下如何使用Java根據(jù)對(duì)象的某個(gè)屬性進(jìn)行去重操作。?? 提供一個(gè)自定義的

    2024年02月04日
    瀏覽(95)
  • Stream流根據(jù)屬性去重

    創(chuàng)建一個(gè)user集合 寫一個(gè)Predict 使用filter方法 結(jié)果: 小結(jié): 實(shí)質(zhì)上是將每個(gè)元素都放到distinctByKey()中的ConcurrentHashMap作為key進(jìn)行過濾,如果key不存在那么就加上去,如果已經(jīng)存在了就不加。所以這種方式的過濾只保留第一個(gè)重復(fù)元素。 結(jié)果與上面的一樣 同時(shí)過濾兩個(gè)屬性 結(jié)

    2024年02月04日
    瀏覽(90)
  • java用stream根據(jù)實(shí)體的某個(gè)屬性對(duì)列表進(jìn)行排序

    用stream流根據(jù)實(shí)體的某個(gè)屬性對(duì)列表進(jìn)行排序 假設(shè)有一個(gè)實(shí)體類 Person,包含兩個(gè)屬性 name 和 age,你可以使用 stream 流的 sorted() 方法來按照某兩個(gè)字段進(jìn)行排序。以下是一個(gè)示例代碼: 在上述代碼中,我們將 personList 轉(zhuǎn)換成流后,調(diào)用了 sorted() 方法,并且使用 Comparator 的

    2024年02月06日
    瀏覽(91)
  • Java8 Stream流List<JSONObject>通過某一屬性進(jìn)行排序

    List對(duì)象 1.首先你需要list.parallelStream().sorted 進(jìn)行流處理,使用parallelStream可以充分調(diào)度多核CPU。 2.使用Comparator.comparing進(jìn)行排序,reversed()進(jìn)行倒序排列,thenComparing進(jìn)行下一個(gè)排序。 3.Comparator.comparing()里面的內(nèi)容,也是就是Object::getter,例如Test::getName 4.最后格式化為需要的格式

    2024年02月12日
    瀏覽(94)
  • java 對(duì)象list使用stream根據(jù)某一個(gè)屬性轉(zhuǎn)換成map的幾種方式

    可以使用Java 8中的Stream API將List轉(zhuǎn)換為Map,并根據(jù)某個(gè)屬性作為鍵或值。以下是一些示例代碼: 在這個(gè)示例中,將Person對(duì)象列表轉(zhuǎn)換為Map,其中鍵為Person對(duì)象的name屬性,值為Person對(duì)象本身。 在這個(gè)示例中,將Person對(duì)象列表轉(zhuǎn)換為Map,其中鍵為Person對(duì)象本身,值為Person對(duì)象的

    2024年02月13日
    瀏覽(97)
  • Java8 list多屬性去重

    Java8 list多屬性去重

    大家好,我是三叔,很高興這期又和大家見面了,一個(gè)奮斗在互聯(lián)網(wǎng)的打工人。 在 Java 開發(fā)中,我們經(jīng)常會(huì)面臨對(duì) List 中的對(duì)象屬性去重的需求。然而,當(dāng)需要根據(jù)多個(gè)屬性來進(jìn)行去重時(shí),情況會(huì)稍微復(fù)雜一些。本篇博客將深入探討如何使用 Java 8 的 Stream API 來實(shí)現(xiàn) List 多屬

    2024年02月14日
    瀏覽(440)
  • 使用Java8 Stream流中的Collectors.collectingAndThen()方法去重

    Collectors.collectingAndThen() 根據(jù)對(duì)象屬性進(jìn)行去重操作 Collectors.collectingAndThen()方法屬于java8 Stream流中的 java.util.stream.Collectors ,此類實(shí)現(xiàn)了 java.util.stream.Collector 接口,還提供了大量的方法對(duì)Stream流中的元素進(jìn)行 map 和 reduce 操作 在獲取任務(wù)的時(shí)候,會(huì)出現(xiàn)id重復(fù)的狀況,利用 Co

    2024年02月09日
    瀏覽(103)
  • Stream流實(shí)踐(二):list 對(duì)象數(shù)組根據(jù)某字段去重的三種基本思路

    相信大家對(duì)于list簡單數(shù)組的去重很熟悉了,例如以下代碼 那我們來探討下,對(duì)于list中保存為對(duì)象的數(shù)組,根據(jù)內(nèi)部對(duì)象的 某一個(gè)字段 去重有什么好的思路呢? 給出一個(gè)簡單的Student對(duì)象 大家學(xué)廢了嗎?

    2024年02月16日
    瀏覽(370)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包