一、重构遗留代码
为了进一步解释如何重构一流代码,本节将距离说明如何将一段使用循环进行集合操作的代码,重构成基于Stream的操作。
假定选取一组专辑,找出其中所有长度大于一分钟的曲目名称。下面是一个例子,首先初始化一个set对象,用来保存找到的曲目名称。然后使用for循环遍历所有专辑,每次循环中在使用一个for循环遍历每张专辑的每首曲目,检查其长度是否大于60秒,如果是,则将该曲目的名称加入set对象。
例如:遗留代码:找出代码大于一分钟的曲目
1 private static Set<String> findLongTracks(List<Album> albums) 2 { 3 Set<String> trackNames=new HasSet(); 4 for(Album album:albums) 5 { 6 for(Track track:album.getTrackList()) 7 { 8 if(track.getLength()>60) 9 { 10 String name=track.getName(); 11 trackNames.add(name); 12 } 13 } 14 15 } 16 return trackNames; 17 }1、重构第一步
public Set<string> findLongTracks(List<Album> albums){ Set<String> trackNames=new HashSet<>(); albums.stream() .forEach(album->{ album.getTracks() .forEach(treack->{ if(track.getLength()>60) { string name =track.getName(); trackNames.add(name); } });});return trackNames;}在本次重构中,虽然用了流,但是没有发挥它的作用。事实上,重构后的代码还不如原来代码。
因此,要继续重构我们就应该找突破口,其中最内层的foreach就是突破口。最内层的foreach方法有三个功用:找出长度大于一分钟的曲目,得到符合条件的曲目名称,将曲目名称加入集合Set。这就意味着需要三项Stream的操作:
①找出满足条件的曲目是filter功能;
②得到曲目名称是map功能;
③终结操作可使用foreach方法将曲目名称加入一个集合。
2、重构的第二步
public Set<String> findLongTreacks(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));} );}虽然做了改进但是代码还是很冗长。
理想的操作,莫过于找到一种方法,将专辑转化一个曲目的stream。任何时候想转换或者替代代码,都该使用map操作。这里将使用比map更复杂的flatMap操作,把多个Stream合并成一个Stream并返回。将foreach方法替换成flatMap后。
3、重构代码的第三部
public Set<String> findLongTracks(List<Album> albums) { Set<String> trackName=new HaashSet(); albums.stream() .flatmap(album->album.getTracks()) .filter(track->track.getLength()>60) .map(track->track.getName()) .foreach(name->trackName.add(name)); return trackNames; }上面的代码中使用一组简洁的方法调用替换掉了两个嵌套的for循环,看起来清晰许多。但是我们还可以继续修改,继续替换到最后一个for循环。
4、重构代码
public Set<String> findLongTracks(List<Album> albums){ return album.stream() .flatMao(album->album.getTracks()) .filter(track->track.getLength()>60) .map(track->track.getName()) .collect(toSet()); }
时间: 2024-11-05 22:45:48