Java8學習筆記-12:整合操作示例

第一個問題描述:
找出某張專輯上所有樂隊的國籍。藝術家列表里既有個人,也有 樂隊涂邀。利用一點領域知識,假定一般樂隊名以定冠詞 The 開頭库继。當然這不是絕對的,但也 差不多。
找出某張專輯上所有樂隊的國籍眯分。藝術家列表里既有個人,也有 樂隊。假定一般樂隊名以定冠詞 The 開頭柒桑。
首先, 可將這個問題分解為如下幾個步驟弊决。

  1. 找出專輯上的所有表演者。
  2. 分辨出哪些表演者是樂隊魁淳。
  3. 找出每個樂隊的國籍飘诗。
  4. 將找出的國籍放入一個集合与倡。
    現(xiàn)在,找出每一步對應的 Stream API 就相對容易了:
  5. Album 類有個 getMusicians 方法,該方法返回一個 Stream 對象,包含整張專輯中所有的
    表演者;
  6. 使用 filter 方法對表演者進行過濾,只保留樂隊;
  7. 使用 map 方法將樂隊映射為其所屬國家;
  8. 使用 collect(Collectors.toList()) 方法將國籍放入一個列表。
    最后,整合所有的操作,就得到如下代碼:
     Set<String> origins = album.getMusicians()
                                .filter(artist -> artist.getName().startsWith("The"))
                                .map(artist -> artist.getNationality())
                                .collect(toSet());

通過重構將現(xiàn)有代碼改寫為Lambada形式
問題描述:假定選定一組專輯,找出其中所有長度大于 1 分鐘的曲目名稱

//遺留代碼:
public Set<String> findLongTracks(List<Album> albums) { 
      Set<String> trackNames = new HashSet<>();
        for (Album album : albums) {
            for (Track track : album.getTrackList()) {
                if (track.getLength() > 60) {
                    String name = track.getName();
                    trackNames.add(name);
                }
            }
        }
        return trackNames;
```
如果仔細閱讀上面的這段代碼,就會發(fā)現(xiàn)幾組嵌套的循環(huán)昆稿。僅通過閱讀這段代碼很難看出 它的編寫目的,那就來重構一下(使用流來重構該段代碼的方式很多,下面介紹的只是其 中一種纺座。事實上,對 Stream API 越熟悉,就越不需要細分步驟。之所以在示例中一步一步 地重構,完全是出于幫助大家學習的目的,在工作中無需這樣做)貌嫡。
第一步要修改的是 for 循環(huán)比驻。首先使用 Stream 的 forEach 方法替換掉 for 循環(huán),但還是暫 時保留原來循環(huán)體中的代碼,這是在重構時非常方便的一個技巧该溯。調(diào)用 stream 方法從專輯 列表中生成第一個 Stream,同時不要忘了在上一節(jié)已介紹過,getTracks 方法本身就返回 一個 Stream 對象岛抄。經(jīng)過第一步重構后,代碼如下所示:
```
//第一次重構:找出長度大于 1 分鐘的曲目
public Set<String> findLongTracks(List<Album> albums) {
        Set<String> trackNames = new HashSet<>();
        albums.stream()
                .forEach(album -> {
                    album.getTracks()
                            .forEach(track -> {
                                if (track.getLength() > 60) {
                                    String name = track.getName();
                                    trackNames.add(name);
                                }
                            });
                });
        return trackNames;
    }
```
在第一次重構中,雖然使用了流,但是并沒有充分發(fā)揮它的作用。事實上,重構后的代 碼還不如原來的代碼好——天哪!因此,是時候引入一些更符合流風格的代碼了,最內(nèi)層 的 forEach 方法正是主要突破口狈茉。
最內(nèi)層的 forEach 方法有三個功用:找出長度大于 1 分鐘的曲目,得到符合條件的曲目名 稱,將曲目名稱加入集合 Set夫椭。這就意味著需要三項 Stream 操作:找出滿足某種條件的曲 目是 filter 的功能,得到曲目名稱則可用 map 達成,終結操作可使用 forEach 方法將曲目
名稱加入一個集合。用以上三項 Stream 操作將內(nèi)部的 forEach 方法拆分后,代碼如下所示:
```
//第二次重構:找出長度大于 1 分鐘的曲目
public Set<String> findLongTracks(List<Album> albums) {
        Set<String> trackNames = new HashSet<>();
        albums.stream()
                .forEach(album -> {
                    album.getTracks()
                            .filter(track -> track.getLength() > 60)
                            .map(track -> track.getName())
                            .forEach(name -> trackNames.add(name));
                });
        return trackNames;
    }
```
現(xiàn)在用更符合流風格的操作替換了內(nèi)層的循環(huán),但代碼看起來還是冗長繁瑣氯庆。將各種流嵌 套起來并不理想,最好還是用干凈整潔的順序調(diào)用一些方法蹭秋。
理想的操作莫過于找到一種方法,將專輯轉(zhuǎn)化成一個曲目的 Stream。眾所周知,任何時候 想轉(zhuǎn)化或替代代碼,都該使用 map 操作堤撵。這里將使用比 map 更復雜的 flatMap 操作,把多個 Stream 合并成一個 Stream 并返回仁讨。將 forEach 方法替換成 flatMap 后,代碼如下所示:
```
//第三次重構:找出長度大于 1 分鐘的曲目
public Set<String> findLongTracks(List<Album> albums) {
        Set<String> trackNames = new HashSet<>();
        albums.stream()
                .flatMap(album -> album.getTracks())
                .filter(track -> track.getLength() > 60)
                .map(track -> track.getName())
                .forEach(name -> trackNames.add(name));
        return trackNames;
    }
```
上面的代碼中使用一組簡潔的方法調(diào)用替換掉兩個嵌套的 for 循環(huán),看起來清晰很多。然 而至此并未結束,仍需手動創(chuàng)建一個 Set 對象并將元素加入其中,但我們希望看到的是整 個計算任務由一連串的 Stream 操作完成实昨。
到目前為止,雖然還未展示轉(zhuǎn)換的方法,但已有類似的操作洞豁。就像使用 collect(Collectors. toList()) 可以將 Stream 中的值轉(zhuǎn)換成一個列表,使用 collect(Collectors.toSet()) 可以將 Stream 中的值轉(zhuǎn)換成一個集合。因此,將最后的 forEach 方法替換為 collect,并刪掉變量 trackNames,代碼如下所示:
```
//第四次重構:找出長度大于 1 分鐘的曲目
public Set<String> findLongTracks(List<Album> albums) {
        return albums.stream()
                .flatMap(album -> album.getTracks())
                .filter(track -> track.getLength() > 60)
                .map(track -> track.getName())
                .collect(Collectors.toSet());
    }
```
簡而言之,選取一段遺留代碼進行重構,轉(zhuǎn)換成使用流風格的代碼荒给。最初只是簡單地使用流,但沒有引入任何有用的流操作丈挟。隨后通過一系列重構,最終使代碼更符合使用流的風 格。在上述步驟中我們沒有提到一個重點,即編寫示例代碼的每一步都要進行單元測試, 保證代碼能夠正常工作志电。重構遺留代碼時,這樣做很有幫助曙咽。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市挑辆,隨后出現(xiàn)的幾起案子例朱,更是在濱河造成了極大的恐慌,老刑警劉巖鱼蝉,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洒嗤,死亡現(xiàn)場離奇詭異,居然都是意外死亡蚀乔,警方通過查閱死者的電腦和手機烁竭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吉挣,“玉大人派撕,你說我怎么就攤上這事婉弹。” “怎么了终吼?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵镀赌,是天一觀的道長。 經(jīng)常有香客問我际跪,道長商佛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任姆打,我火速辦了婚禮良姆,結果婚禮上,老公的妹妹穿的比我還像新娘幔戏。我一直安慰自己玛追,他們只是感情好,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布闲延。 她就那樣靜靜地躺著痊剖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪垒玲。 梳的紋絲不亂的頭發(fā)上陆馁,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音合愈,去河邊找鬼叮贩。 笑死,一個胖子當著我的面吹牛想暗,可吹牛的內(nèi)容都是我干的妇汗。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼说莫,長吁一口氣:“原來是場噩夢啊……” “哼杨箭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起储狭,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤互婿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辽狈,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慈参,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年刮萌,在試婚紗的時候發(fā)現(xiàn)自己被綠了驮配。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖壮锻,靈堂內(nèi)的尸體忽然破棺而出琐旁,到底是詐尸還是另有隱情,我是刑警寧澤猜绣,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布灰殴,位于F島的核電站,受9級特大地震影響掰邢,放射性物質(zhì)發(fā)生泄漏牺陶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一辣之、第九天 我趴在偏房一處隱蔽的房頂上張望掰伸。 院中可真熱鬧,春花似錦召烂、人聲如沸碱工。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至历筝,卻和暖如春酗昼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梳猪。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工麻削, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人春弥。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓呛哟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匿沛。 傳聞我的和親對象是個殘疾皇子扫责,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 扯淡 在準備學 Java8 之前,我以為不會很難逃呼。所以鳖孤,我就決定一邊學 Java8,一邊寫博客抡笼。當我準備寫這篇博客...
    小白聊技術閱讀 433評論 0 1
  • 5.1 方法引用 Lambda 表達式有一個常見的用法;Lanbda 表達式經(jīng)常 調(diào)用參數(shù)苏揣。比如想得到藝術家的姓名...
    伊凡的一天閱讀 1,285評論 0 3
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)推姻,斷路器平匈,智...
    卡卡羅2017閱讀 134,716評論 18 139
  • 3.1 從外部迭代到內(nèi)部迭代 外部迭代 使用迭代器計算來自倫敦的藝術家人數(shù): int count=0;for (A...
    伊凡的一天閱讀 424評論 0 2
  • Int Double Long 設置特定的stream類型, 提高性能,增加特定的函數(shù) 無存儲增炭。stream不是一...
    patrick002閱讀 1,277評論 0 0