一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java函數式編程(四):在集合中查找元素

Java函數式編程(四):在集合中查找元素

2019-11-29 16:19deepinmind JAVA教程

這篇文章主要介紹了Java函數式編程(四):在集合中查找元素,本文是系列文章的第4篇,其它篇章請參閱相關文章,需要的朋友可以參考下

查找元素

現在我們對這個設計優雅的轉化集合的方法已經不陌生了,但它對查找元素卻也是無能為力。不過filter方法卻是為這個而生的。

我們現在要從一個名字列表中,取出那些以N開頭的名字。當然可能一個也沒有,結果可能是個空集合。我們先用老方法實現一把。

 

復制代碼代碼如下:

final List<String> startsWithN = new ArrayList<String>();
for(String name : friends) {
if(name.startsWith("N")) {
startsWithN.add(name);
}
}

 

這么簡單的事件,寫了這么多代碼,也夠啰嗦的了。我們先創建了一個變量,然后把它初始為一個空集合。然后遍歷原來的集合,查找那些以指定字母開頭的名字。如果找到,就插入到集合里。

我們用filter方法來重構一下上面這段代碼,看看它的威力到底如何。

 

復制代碼代碼如下:

final List<String> startsWithN =
friends.stream()
.filter(name -> name.startsWith("N"))
.collect(Collectors.toList());

 

filter方法接收一個返回布爾值的lambda表達式。如果表達式結果為true,運行上下文中的那個元素就會被添加到結果集中;如果不是,就跳過它。最終返回的是一個Steam,它里面只包含那些表達式返回true的元素。最后我們用一個collect方法把這個集合轉化成一個列表——在后面52頁的使用collect方法和Collecters類中,我們會對這個方法進去更深入的探討。

我們來打印一下這個結果集中的元素:

復制代碼代碼如下:

System.out.println(String.format("Found %d names", startsWithN.size()));


從輸出結果很明顯能看出來,這個方法把集合中匹配的元素全都找出來了。

復制代碼代碼如下:

Found 2 names


filter方法和map方法一樣,也返回了一個迭代器,不過它們也就這點相同而已了。map返回的集合和輸入集合大小是一樣的,而filter返回的可不好說。它返回的集合的大小區間,從0一直到輸入集的元素個數。和map不一樣的是,filter返回的是輸入集的一個子集。

 

到現在為止,lambda表達式帶來的代碼簡潔性讓我們很滿意,不過如果不注意的話,代碼冗余的問題就開始慢慢滋長了。下面我們來討論下這個問題。

lambda表達式的重用

lambda表達式看起來很簡潔,實際上一不小心很容易就出現代碼冗余了。冗余會導致代碼質量低下,難以維護;如果我們想做一個改動,得把好幾處相關的代碼都一起改掉才行。

避免冗余還可以幫忙我們提升性能。相關的代碼都集中在一個地方,這樣我們分析它的性能表現,然后優化這一處的代碼,很容易就能提升代碼的性能。

現在我們來看下為什么使用lambda表達式容易導致代碼冗余,同時考慮如何去避免它。

復制代碼代碼如下:

final List<String> friends =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
final List<String> editors =
Arrays.asList("Brian", "Jackie", "John", "Mike");
final List<String> comrades =
Arrays.asList("Kate", "Ken", "Nick", "Paula", "Zach");
We want to filter out names that start with a certain letter.


我們希望過濾一下某個字母開頭的名字。先用filter方法簡單地實現一下。

復制代碼代碼如下:

final long countFriendsStartN =
friends.stream()
.filter(name -> name.startsWith("N")).count();
final long countEditorsStartN =
editors.stream()
.filter(name -> name.startsWith("N")).count();
final long countComradesStartN =
comrades.stream()
.filter(name -> name.startsWith("N")).count();


lambda表達式讓代碼看起來很簡潔,不過它不知不覺的帶來了代碼的冗余。在上面這個例子中,如果想改一下lambda表達式,我們得改不止一處地方——這可不行。幸運的是,我們可以把lambda表達式賦值給變量,然后對它們進行重用,就像使用對象一樣。

 

filter方法,lambda表達式的接收方,接收的是一個java.util.function.Predicate函數式接口的引用。在這里,Java編譯器又派上用場了,它用指定的lambda表達式生成了Predicate的test方法的一個實現。現在我們可以更明確的讓Java編譯器去生成這個方法,而不是在參數定義的地方再生成。在上面例子中,我們可以明確的把lambda表達式存儲到一個Predicate類型的引用里面,然后再把這個引用傳遞給filter方法;這樣做很容易就避免了代碼冗余。

我們來重構前面這段代碼,讓它符合DRY的原則吧。(Don't Repeat Yoursef——DRY——原則,可以參看The Pragmatic Programmer: From Journeyman to Master[HT00],一書)。

 

復制代碼代碼如下:

final Predicate<String> startsWithN = name -> name.startsWith("N");
final long countFriendsStartN =
friends.stream()
.filter(startsWithN)
.count();
final long countEditorsStartN =
editors.stream()
.filter(startsWithN)
.count();
final long countComradesStartN =
comrades.stream()
.filter(startsWithN)
.count();

 

現在不用再重復寫那個lambda表達式了,我們只寫了一次,并把它存儲到了一個叫startsWithN的Predicate類型的引用里面。這后面的三個filter調用里,Java編譯器看到在Predicate偽裝下的lambda表達式,笑而不語,默默接收了。

這個新引入的變量為我們消除了代碼冗余。不過不幸的是,后面我們就會看到,敵人很快又回來報仇雪恨了,我們再看看有什么更厲害的武器能替我們消滅它們。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91香蕉官网| 亚洲H成年动漫在线观看不卡 | xnxx老师 | 久久无码人妻AV精品一区 | 免费在线观看网址大全 | www.日日日| 丝袜捆绑调教视频免费区 | 春意影院午夜爽爽爽免费 | 亚洲另类老妇videos | 亚洲高清一区二区三区四区 | 99久久精品免费看国产四区 | 波多野 在线 | 性奴公司 警花 | 乳女教师欲乱动漫无修版动画3d | 国模孕妇季玥337p人体 | 波多野结衣女老师 | 亚洲人成网站在线观看90影院 | 91精品国产91热久久p | 国内会所按摩推拿国产 | 青青草国产一区二区三区 | 成人啪啪漫画全文阅读 | 欧美专区视频 | 国产成人v爽在线免播放观看 | tiny4k欧美极品在线 | 日本三级在丈面前被耍了 | 好爽好深好猛好舒服视频上 | 国产九九在线 | 高清毛片一区二区三区 | 日韩精品欧美国产精品亚 | 精品久久伦理中文字幕 | 成人欧美一区在线视频在线观看 | 成人亚洲欧美综合 | 和直男装修工在工地啪 | 色依依视频视频在线观看 | 激情综合色啪啪小说 | 精品国产欧美一区二区 | 四虎新网址 | 国产精品亚洲综合久久 | 日处女b | 亚洲老头老太hd | 欧美久久一区二区三区 |