遺留代碼:找出長度大于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方法,他是一個終結方法。