JAVA 8 Stream操作List和Map以及復(fù)合拼裝對(duì)象

1 程序員對(duì)什么數(shù)據(jù)類型操作做多?
毋庸置疑,那就是集合類的數(shù)據(jù)類型。不管是LIST,MAP,SET或者是python的字典。
2 List的相關(guān)操作java流操作:
場景一 java8的LIST和map進(jìn)行按某個(gè)條件分組,然后根據(jù)特定字段去重,最后統(tǒng)計(jì)去重后每組的個(gè)數(shù)

import java.util.*;

public class GroupByExample {
    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        list.add(new Person("John", "Male", 20));
        list.add(new Person("Alice", "Female", 18));
        list.add(new Person("Bob", "Male", 20));
        list.add(new Person("Carol", "Female", 18));
        list.add(new Person("David", "Male", 20));
 
       // 根據(jù)某個(gè)字段分組,并返回Map<key,List<Object>>的數(shù)據(jù)格式
       // Group by gender 
        Map<String, List<Person>> genderGroup = list.stream().collect(
            Collectors.groupingBy(Person::getGender));
 
      // 根據(jù)某個(gè)字段分組,并返回Map<key,Integer>的計(jì)數(shù)格式,也就是拿到這個(gè)key有多少條聚合的數(shù)據(jù)。
      // Count the number of persons in each group
        Map<String, Long> countByGender = list.stream().collect(
            Collectors.groupingBy(Person::getGender, Collectors.counting()));
 
        //多個(gè)字段進(jìn)行分組,并返回Map<key,Integer>的計(jì)數(shù)格式,也就是拿多個(gè)字段進(jìn)行組合分組
        // Group by gender and age
        Map<String, Map<Integer, List<Person>>> ageGroup = list.stream().collect(
            Collectors.groupingBy(Person::getGender,
                Collectors.groupingBy(Person::getAge)));
 
        // Count the number of persons in each gender and age group
        Map<String, Map<Integer, Long>> countByGenderAndAge = list.stream().collect(
            Collectors.groupingBy(Person::getGender,
                Collectors.groupingBy(Person::getAge, Collectors.counting())));
        //按性別分組,然后根據(jù)name去重
        // Group by gender and remove duplicates based on name
        Map<String, List<Person>> distinctNameByGender = list.stream().collect(
                Collectors.groupingBy(Person::getGender,
                        Collectors.collectingAndThen(
                                toCollection(() ->
                                        new TreeSet<>(Comparator.comparing(Person::getName))
                                ),ArrayList::new)
                ));
    }
}

POJO對(duì)象

class Person {
    private String name;
    private String gender;
    private int age;
 
    public Person(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
   //  省略setter and getter
}

JAVA LIST 多個(gè)字段 group by的時(shí)候,我一般喜歡封裝一個(gè)方法,加一個(gè)連接符來處理。比如我有一個(gè)對(duì)象,叫
ActualSortingLog,當(dāng)前分揀日志, 我希望根據(jù)sortingTime和PipeLine進(jìn)行分組。那就可以創(chuàng)建一個(gè)叫
fetchGroupKey的方法

  /**
     * 
     * 根據(jù)sortingTime和PipeLine進(jìn)行分組
     * @param actualSortingLog
     * @return
     */
    private String fetchGroupKey(ActualSortingLog actualSortingLog) {
       return actualSortingLog.getSortingTime() +"#"+ user.getPipeLine();
    }

這樣好處是解耦,也方便擴(kuò)展,代碼也可讀。進(jìn)一步,如果希望對(duì)字段做一些處理,再分組,也就簡單很多。比如
這邊進(jìn)一步,希望按分鐘和pipeLine字段的前3位聚合,同時(shí)時(shí)間格式變?yōu)閥yyyMMddHHmm這種,則代碼如下:

  /**
     * 按分鐘線加pipeline前三位進(jìn)行聚合
     *
     * @param actualSortingInfoDTO
     * @return
     */
    private String makeGroupKeyMinuteWithDeviceCode(ActualSortingInfoDTO actualSortingInfoDTO) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
        return dateTimeFormatter.format(LocalDateTimeUtils.longToLocalTime(actualSortingInfoDTO.getSortTime())) + SEPARATOR +
                filterDeviceCode(actualSortingInfoDTO.getPipeline());
    }

當(dāng)然這里我又封裝了時(shí)間工具LocalDateTimeUtils類和設(shè)備編碼切割類filterDeviceCode,是因?yàn)檫@些細(xì)碎的邏輯在后續(xù)的切割和分組中會(huì)經(jīng)常用到。分開也有利于測試和管理。這里就不展開講。

再來說一說List的去重邏輯,首先是簡單去重

@Test
    @DisplayName("list去重測試")
    void testDuplicate() {
        ActualSortingInfoDTO mockData = mockData("001223", "1", 1677037037000L);
        ActualSortingInfoDTO mockData2 = mockData("002331", "2", 1677037037000L);
        // 模擬一個(gè)重復(fù)的sortingId,應(yīng)該會(huì)去重
        ActualSortingInfoDTO duplicateId = mockData("002331", "2", 1677037037001L);
        List<ActualSortingInfoDTO> list = new ArrayList<>();
        list.add(mockData);
        list.add(mockData2);
        list.add(duplicateId);

        List<ActualSortingInfoDTO> distinctList = list.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(simpleTreeSetSupplier()),
                ArrayList::new));
        log.info("簡單去重的數(shù)據(jù)" + distinctList);

        // 復(fù)雜邏輯去重,比如我希望根據(jù)pipeLine的前三位的值是001來去重
        List<ActualSortingInfoDTO> complexDistinctList = list.stream().collect(Collectors.collectingAndThen(
           Collectors.toCollection(distinctPipeLine()),ArrayList::new
        ));
        log.info("復(fù)雜去重的數(shù)據(jù)" + complexDistinctList);

        // list to map,復(fù)雜邏輯去重,比如我希望根據(jù)pipeLine的前三位的值是001和sortingId不等于2來去重,應(yīng)該是保留第一條的數(shù)據(jù)mockData
        Map<String, List<ActualSortingInfoDTO>> distinctMap = ListStreamUtil.group(complexDistinctList,this::makeGroupKeyMinuteWithDeviceCode);
        Assertions.assertEquals(
                distinctMap.get(makeGroupKeyMinuteWithDeviceCode(mockData)).get(0).getPipeline(),"001223");
        Assertions.assertEquals(
                distinctMap.get(makeGroupKeyMinuteWithDeviceCode(mockData)).get(0).getSortingId(),"1");
        distinctMap.forEach((k, v) -> log.info("分組后:" + k + " " + v));
    }

這里也建議對(duì)復(fù)雜的去重方法進(jìn)行封裝,比如我這邊封裝了一個(gè)方法,叫distinctPipeLine,后續(xù)就可以自定義各種去重邏輯了。
自定義去重方法如下:

private Supplier<TreeSet<ActualSortingInfoDTO>> distinctPipeLine() {
        return () -> new TreeSet<>(
                Comparator.comparing(actualSortingInfoDTO ->
                actualSortingInfoDTO.getPipeline().equals("001")
                        && !Objects.equals(actualSortingInfoDTO.getSortingId(), "2")));
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容