實(shí)際開(kāi)發(fā)中Stream流式編程flatMap的使用(兩層for循環(huán))

網(wǎng)上大部分文章介紹時(shí)概念性太強(qiáng),而實(shí)際例子又太少。只知道flatMap是流的扁平化抑堡。但是不知道這么去用涌矢。而這篇文章將以實(shí)際開(kāi)發(fā)的角度帶你去了解flatMap掖举。

源碼中的描述:

The code flatMap() operation has the effect of applying a one-to-many transformation to the elements of the stream, and then flattening the resulting elements into a new stream.

flatMap()的作用是對(duì)流中的元素進(jìn)行1對(duì)多的轉(zhuǎn)換,然后將結(jié)果元素展開(kāi)為新的流娜庇。

這句話的含義是什么塔次?你可以理解為flatMap就是兩層for循環(huán)處理數(shù)據(jù)滨巴。而返回結(jié)果就是flatMap展開(kāi)的流。

1. 數(shù)據(jù)準(zhǔn)備

/**
 * 玩具類
 */
@Data
@AllArgsConstructor
public class Toy {

    private String name;

    private double price;
}
@Data
@AllArgsConstructor
public class Boy {
    private String name;

    private int age;

    private List<Toy> toys;
}
@Data
@AllArgsConstructor
public class Student {

    private String name;
    private String schoolName;
    private String className;
}
public class TestStream {
    private static List<Boy> boys = new ArrayList<>();
    private static List<Student> stus = new ArrayList<>();
    static {


        boys.add(new Boy("tom", 12,
                Arrays.asList(
                        new Toy("飛機(jī)", 9.1),
                        new Toy("坦克", 7.0),
                        new Toy("小熊", 14.0))));

        boys.add(new Boy("tony", 19,
                Arrays.asList(
                        new Toy("玩具槍", 13.1),
                        new Toy("小汽車", 12.2))));


        stus.add(new Student("tom", "衡水中學(xué)", "尖子班"));
        stus.add(new Student("jerry", "黃岡中學(xué)", "普通班"));
        stus.add(new Student("dom", "衡水一中", "文科班"));
    }
}

實(shí)戰(zhàn)使用

1. 對(duì)元素內(nèi)部的集合進(jìn)行處理

第一個(gè)Stream是將boys集合展開(kāi)俺叭,而在flatMap()內(nèi)部恭取,會(huì)將boys集合內(nèi)部集合再次展開(kāi)。

其等效于兩層for循環(huán)熄守,最終得到的結(jié)果是n*m給元素蜈垮。(注:n是外層循環(huán)次數(shù),m是內(nèi)層循環(huán)次數(shù))裕照。

    public static void main(String[] args) {

        //此時(shí)是處理第二個(gè)循環(huán)
        List<Toy> toys = boys.stream().flatMap(
                //將流中元素的數(shù)據(jù)再次展開(kāi)
                b -> b.getToys().stream()).
                    collect(Collectors.toList());
        System.out.println(JSON.toJSONString(toys));
//        等效于
        //因?yàn)槭?:n的關(guān)系攒发,所以最終會(huì)產(chǎn)生n記錄
        List<Toy> tls = new ArrayList<>();
        for (Boy boy : boys) {
            for (Toy toy : boy.getToys()) {
                tls.add(toy);
            }
        }
        //打印數(shù)據(jù)
        System.out.println(JSON.toJSONString(tls));
  }

當(dāng)然在flatMap方法內(nèi)部,可以利用這兩個(gè)流的元素進(jìn)行操作晋南。

    public static void main(String[] args) {
        List<String> collect1 = boys.stream().flatMap(b -> b.getToys().stream().
                filter(t -> t.getPrice() > 12).
                map(t -> {
                    //即可以操作外層元素也可以操作內(nèi)層元素
                    return b.getName() + ":" + t.getName();
                })).collect(Collectors.toList());

        System.out.println(JSON.toJSONString(collect1));
        //等效于:
        List<String> tls1 = new ArrayList<>();
        for (Boy boy : boys) {
            for (Toy toy : boy.getToys()) {
                if (toy.getPrice() > 12) {
                    tls1.add(boy.getName() + ":" + toy.getName());
                }
            }
        }
        System.out.println(JSON.toJSONString(tls1));
    }
}

2. 用于兩個(gè)集合的合并

將兩個(gè)集合合并為一個(gè)集合惠猿,一般寫(xiě)法需要得借助兩層for循環(huán)。

而flatMap()操作的一個(gè)作用就是將兩個(gè)集合合并為一個(gè)集合负间,相當(dāng)于join操作偶妖,若沒(méi)有filter操作,會(huì)產(chǎn)生笛卡爾積現(xiàn)象政溃。

 public static void main(String[] args) {
        List<String> collect = boys.stream().flatMap(b -> stus.stream().
                        //第二層for循環(huán)中處理數(shù)據(jù)
                                filter(s -> b.getName().equals(s.getName())).
                        //將數(shù)據(jù)放入到一個(gè)新的集合中
                                map(Student::getName)
                //結(jié)束第二層循環(huán)
        ).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(collect));
       //等效于
        List<String> data=new ArrayList<>();
        //雙層for循環(huán)處理數(shù)據(jù)
        for (Boy boy : boys) {
            for (Student student : stus) {
                //filter條件
                if(boy.getName().equals(student.getName())){
                    //map子句趾访,將元素放入到新集合中
                    data.add(student.getName());
                }
            }
        }
        System.out.println(JSON.toJSONString(data));
    }

總結(jié):JDK1.8提供了Stream提供的流式操作可以使得開(kāi)發(fā)人員像操作數(shù)據(jù)庫(kù)一樣操作集合。Map相當(dāng)于select映射董虱,而flatMap更像join連接扼鞋。

3. 實(shí)戰(zhàn)運(yùn)用

場(chǎng)景:

表之間存在1:n的關(guān)系,理論上要?jiǎng)?chuàng)建2張表愤诱。但是若使用1張表云头,該表某個(gè)字段使用JSON格式,也可以完成淫半。

目前需求是在該表獲取到某些記錄后溃槐,需要轉(zhuǎn)換為n條記錄。

在數(shù)據(jù)庫(kù)獲取的實(shí)體是:

    //實(shí)體對(duì)象
    @Data
    public static class Student {
        
        private String name;
        //JSON串撮慨,格式[1,2,4]
        private String project;
    }

分析:這個(gè)是對(duì)元素內(nèi)部的集合進(jìn)行處理竿痰。即也是雙層for循環(huán)。

import com.alibaba.fastjson.JSONArray;
import lombok.Data;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 測(cè)試合并流
 *
 */
public class TestFlatMap {


    public static List<Student> stus = new ArrayList<>();

    static {
        Student s1 = new Student();
        s1.setName("黎明");
        s1.setProject("[1,3,5,6]");

        Student s2 = new Student();
        s2.setName("李白");
        s2.setProject("[2,9]");
        stus.add(s1);
        stus.add(s2);
    }

    public static void main(String[] args) {
        test1();
    }
    

    public static void test1() {

        //第一層for循環(huán)是遍歷student對(duì)象
        List<Student> collect = stus.stream().flatMap(s -> {
            String project = s.getProject();
            List<String> ps = JSONArray.parseArray(project, String.class);
            //第二個(gè)for循環(huán)砌溺,是遍歷project對(duì)象影涉。
            return ps.stream().map(p -> {
                //每個(gè)Student的project填充的均是解析后的JSON串的值。
                Student student = new Student();
                BeanUtils.copyProperties(s, student);
                //填充新的屬性
                student.setProject(p);
                return student;
            });
        }).collect(Collectors.toList());  //兩層for循環(huán)結(jié)束后組裝成List

        System.out.println(collect);
    }

    //實(shí)體對(duì)象
    @Data
    public static class Student {

        private String name;
        //JSON串规伐,格式[1,2,4]
        private String project;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蟹倾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鲜棠,老刑警劉巖肌厨,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異豁陆,居然都是意外死亡柑爸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)盒音,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)表鳍,“玉大人,你說(shuō)我怎么就攤上這事祥诽∑┦ィ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵雄坪,是天一觀的道長(zhǎng)厘熟。 經(jīng)常有香客問(wèn)我,道長(zhǎng)维哈,這世上最難降的妖魔是什么绳姨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮笨农,結(jié)果婚禮上就缆,老公的妹妹穿的比我還像新娘。我一直安慰自己谒亦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布空郊。 她就那樣靜靜地躺著份招,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狞甚。 梳的紋絲不亂的頭發(fā)上锁摔,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音哼审,去河邊找鬼谐腰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛涩盾,可吹牛的內(nèi)容都是我干的十气。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼春霍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼砸西!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤芹枷,失蹤者是張志新(化名)和其女友劉穎衅疙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鸳慈,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饱溢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了走芋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片理朋。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绿聘,靈堂內(nèi)的尸體忽然破棺而出嗽上,到底是詐尸還是另有隱情,我是刑警寧澤熄攘,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布兽愤,位于F島的核電站,受9級(jí)特大地震影響挪圾,放射性物質(zhì)發(fā)生泄漏浅萧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一哲思、第九天 我趴在偏房一處隱蔽的房頂上張望洼畅。 院中可真熱鬧,春花似錦棚赔、人聲如沸帝簇。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)丧肴。三九已至,卻和暖如春胧后,著一層夾襖步出監(jiān)牢的瞬間芋浮,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工壳快, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纸巷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓眶痰,卻偏偏與公主長(zhǎng)得像瘤旨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凛驮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355