JAVA 8 Stream操作List和Map以及復合拼裝對象

1 程序員對什么數(shù)據(jù)類型操作做多丹壕?
毋庸置疑捌木,那就是集合類的數(shù)據(jù)類型。不管是LIST,MAP,SET或者是python的字典职辅。
2 List的相關操作java流操作:
場景一 java8的LIST和map進行按某個條件分組,然后根據(jù)特定字段去重聂示,最后統(tǒng)計去重后每組的個數(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ù)某個字段分組域携,并返回Map<key,List<Object>>的數(shù)據(jù)格式
       // Group by gender 
        Map<String, List<Person>> genderGroup = list.stream().collect(
            Collectors.groupingBy(Person::getGender));
 
      // 根據(jù)某個字段分組,并返回Map<key,Integer>的計數(shù)格式鱼喉,也就是拿到這個key有多少條聚合的數(shù)據(jù)秀鞭。
      // Count the number of persons in each group
        Map<String, Long> countByGender = list.stream().collect(
            Collectors.groupingBy(Person::getGender, Collectors.counting()));
 
        //多個字段進行分組,并返回Map<key,Integer>的計數(shù)格式扛禽,也就是拿多個字段進行組合分組
        // 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對象

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 多個字段 group by的時候,我一般喜歡封裝一個方法编曼,加一個連接符來處理豆巨。比如我有一個對象,叫
ActualSortingLog掐场,當前分揀日志往扔, 我希望根據(jù)sortingTime和PipeLine進行分組。那就可以創(chuàng)建一個叫
fetchGroupKey的方法

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

這樣好處是解耦熊户,也方便擴展萍膛,代碼也可讀。進一步敏弃,如果希望對字段做一些處理卦羡,再分組,也就簡單很多麦到。比如
這邊進一步绿饵,希望按分鐘和pipeLine字段的前3位聚合,同時時間格式變?yōu)閥yyyMMddHHmm這種瓶颠,則代碼如下:

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

當然這里我又封裝了時間工具LocalDateTimeUtils類和設備編碼切割類filterDeviceCode拟赊,是因為這些細碎的邏輯在后續(xù)的切割和分組中會經常用到。分開也有利于測試和管理粹淋。這里就不展開講吸祟。

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

@Test
    @DisplayName("list去重測試")
    void testDuplicate() {
        ActualSortingInfoDTO mockData = mockData("001223", "1", 1677037037000L);
        ActualSortingInfoDTO mockData2 = mockData("002331", "2", 1677037037000L);
        // 模擬一個重復的sortingId,應該會去重
        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);

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

        // list to map,復雜邏輯去重屋匕,比如我希望根據(jù)pipeLine的前三位的值是001和sortingId不等于2來去重,應該是保留第一條的數(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));
    }

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

private Supplier<TreeSet<ActualSortingInfoDTO>> distinctPipeLine() {
        return () -> new TreeSet<>(
                Comparator.comparing(actualSortingInfoDTO ->
                actualSortingInfoDTO.getPipeline().equals("001")
                        && !Objects.equals(actualSortingInfoDTO.getSortingId(), "2")));
    }
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末纤虽,一起剝皮案震驚了整個濱河市乳绕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逼纸,老刑警劉巖洋措,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杰刽,居然都是意外死亡菠发,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門专缠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雷酪,“玉大人,你說我怎么就攤上這事涝婉「缌Γ” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵墩弯,是天一觀的道長吩跋。 經常有香客問我,道長渔工,這世上最難降的妖魔是什么锌钮? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮引矩,結果婚禮上梁丘,老公的妹妹穿的比我還像新娘。我一直安慰自己旺韭,他們只是感情好氛谜,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著区端,像睡著了一般值漫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上织盼,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天杨何,我揣著相機與錄音,去河邊找鬼沥邻。 笑死危虱,一個胖子當著我的面吹牛,可吹牛的內容都是我干的唐全。 我是一名探鬼主播槽地,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捌蚊?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤近弟,失蹤者是張志新(化名)和其女友劉穎缅糟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祷愉,經...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡窗宦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了二鳄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赴涵。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖订讼,靈堂內的尸體忽然破棺而出髓窜,到底是詐尸還是另有隱情,我是刑警寧澤欺殿,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布寄纵,位于F島的核電站,受9級特大地震影響脖苏,放射性物質發(fā)生泄漏程拭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一棍潘、第九天 我趴在偏房一處隱蔽的房頂上張望恃鞋。 院中可真熱鬧,春花似錦亦歉、人聲如沸恤浪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽资锰。三九已至,卻和暖如春阶祭,著一層夾襖步出監(jiān)牢的瞬間绷杜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工濒募, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鞭盟,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓瑰剃,卻偏偏與公主長得像齿诉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內容