天天看點

《java8函數式程式設計》——使用函數式程式設計重構代碼

遺留代碼:找出長度大于1分鐘的歌曲
public Set<String> findLongTracks(List<Album> albums){
    Set<String> tracksNames=new HashSet<>();
    for(Album album:albums){
        for(Track track:album.getTrackList()){
            if(track.getLength()>){
                String name=track.getName();
                trackNames.add(name);
            }
        }
    }
    return trackNames;
}
           
重構第一步
public Set<String> findLongTracks(List<Album> albums){
    Set<String> tracksNames=new HashSet<>();
    //對象中定義的getTracks方法會傳回一個Stream對象
    albums.stream()
            .forEach(album->{
                album.getTracks()
                        .forEach(track->{
                            if(track.getLength()>){
                                    trackNames.add(track.getNames)
                                        }
                                   });//這裡為什麼需要加分号?
                 });
    return trackNames;
}
           
重構第二步
public Set<String> findLongTracks(List<Album> albums){
    Set<String> tracksNames=new HashSet<>();
    albums.stream()
            .forEach(album->{
                album.getTracks()
                        .filter(track->track.getLength()>)
                        .map(track->track.getName())
                        .forEach(name->trackNames.add(name));
                 });
    return trackNames;
}
           
重構第三步
public Set<String> findLongTracks(List<Album> albums){
    Set<String> tracksNames=new HashSet<>();
    //将多個Stream合并為一個
    albums.stream()
            .flatMap(album->album.getTracks()).
                        .filter(track->track.getLength()>)
                        .map(track->track.getName())
                        .forEach(name->trackNames.add(name));
    return trackNames;
}
           
重構第四步
public Set<String> findLongTracks(List<Album> albums){
    return albums.stream()
                .flatMap(album->album.getTracks()).
                        .filter(track->track.getLength()>)
                        .map(track->track.getName())
                        .collect(toSet());
}
           

Lambda表達式的宗旨是擷取值而不是變量!是以盡量不要産生垃圾變量來儲存中間結果。

書上的一段描述:Lambda表達式描述了資料上的操作,明确了要達成什麼轉化,而不是說明如何轉化。這種方式寫出的代碼,存在的缺陷更少。

怎樣了解這段話呢?

這說明一段安全的程式應該着重于從原始資料轉化成結果,而不在于過程,并且不要把資料轉化過程暴露出來(即産生一系列中間變量)也就是不必說明資料是如何轉化的,隻要最終達成轉化即可!

明确要達成什麼轉化,而不是說明如何轉化的另外一層含義在于寫出的函數沒有副作用!(沒有副作用的函數不會改變程式或外界的狀态)

是以無論何時,将Lambda表達式傳給Stream上的高階函數,都應該盡量避免副作用。唯一的例外是forEach方法,他是一個終結方法。