亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java函數式編程(二):集合的使用

 更新時間:2014年09月25日 11:47:02   作者:deepinmind  
這篇文章主要介紹了Java函數式編程(二):集合的使用,本文著重講解了遍歷列表的一些方法,需要的朋友可以參考下

第二章:集合的使用

我們經常會用到各種集合,數字的,字符串的還有對象的。它們無處不在,哪怕操作集合的代碼要能稍微優(yōu)化一點,都能讓代碼清晰很多。在這章中,我們探索下如何使用lambda表達式來操作集合。我們用它來遍歷集合,把集合轉化成新的集合,從集合中刪除元素,把集合進行合并。

遍歷列表

遍歷列表是最基本的一個集合操作,這么多年來,它的操作也發(fā)生了一些變化。我們使用一個遍歷名字的小例子,從最古老的版本介紹到現在最優(yōu)雅的版本。

用下面的代碼我們很容易創(chuàng)建一個不可變的名字的列表:

復制代碼 代碼如下:

final List<String> friends =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
System.out.println(friends.get(i));
}

下面這是最常見的一種遍歷列表并打印的方法,雖然也最一般:

復制代碼 代碼如下:

for(int i = 0; i < friends.size(); i++) {
System.out.println(friends.get(i));
}

我把這種方式叫做自虐型寫法——又啰嗦又容易出錯。我們得停下來好好想想,"是i<還是i<=呢?"這只有當我們需要操作具體某個元素的時候才有意義,不過即便這樣,我們還可以使用堅持不可變原則的函數式風格來實現,這個我們很快會討論到。

Java還提供了一種相對先進的for結構。

復制代碼 代碼如下:

collections/fpij/Iteration.java
for(String name : friends) {
System.out.println(name);
}

在底層,這種方式的迭代是使用Iterator接口來實現的,調用了它的hasNext和next方法。 這兩種方式都屬于外部迭代器,它們把如何做和想做什么揉到了一起。我們顯式的控制迭代,告訴它從哪開始到哪結束;第二個版本則在底層通過Iterator的方法來做這些。顯式的操作下,還可以用break和continue語句來控制迭代。 第二個版本比第一個少了點東西。如果我們不打算修改集合的某個元素的話,它的方式比第一個要好。不過這兩種方式都是命令式的,在現在的Java中應該摒棄這種方式。 改成函數式原因有這幾個:

1.for循環(huán)本身是串行的,很難進行并行化。
2.這樣的循環(huán)是非多態(tài)的;所得即所求。我們直接把集合傳給for循環(huán),而不是在集合上調用一個方法(支持多態(tài))來執(zhí)行特定的操作。
3.從設計層面來說,這樣 寫的代碼違反了“Tell,Don't Ask”的原則 。我們請求執(zhí)行一次迭代,而不是把迭代留給底層庫來執(zhí)行。

是時候從老的命令式編程轉換到更優(yōu)雅的內部迭代器的函數式編程了。使用內部迭代器后我們把很多具體操作都扔給了底層方法庫來執(zhí)行,你可以更專注于具體的業(yè)務需求。底層的函數會負責進行迭代的。我們先用一個內部迭代器來枚舉一下名字列表。

Iterable接口在JDK8中得到加強,它有一個專門的名字叫forEach,它接收一個Comsumer類型的參數。如名字所說,Consumer的實例正是通過它的accept方法消費傳遞給它的對象的。我們用一個很熟悉的匿名內部類的語法來使用下這個forEach方法:

復制代碼 代碼如下:

friends.forEach(new Consumer<String>() { public void accept(final String name) {
System.out.println(name); }
});

我們調用了friends集合上的forEach方法,給它傳遞了一個Consumer的匿名實現。這個forEach方法從對集合中的每一個元素調用傳入的Consumer的accept方法,讓它來處理這個元素。在這個示例中我們只是打印了一下它的值,也就是這個名字。 我們來看下這個版本的輸出結果,和上兩個的結果 是一樣的:

復制代碼 代碼如下:

Brian
Nate
Neal
Raju
Sara
Scott

我們只改了一個地方:我們拋棄了過時的 for循環(huán),使用了新的內部迭代器。好處是,我們不用指定如何迭代這個集合,可以更專注于如何處理每一個元素。缺點是,代碼看起來更啰嗦了——這簡直要把新的編碼風格帶來的喜悅沖的一干二凈了。所幸的是,這個很容易改掉,這正是lambda表達式和新的編譯器的威力大展身手的時候了。我們再做一點修改,把匿名內部類換成lambda表達式。
復制代碼 代碼如下:

friends.forEach((final String name) -> System.out.println(name));

這樣看起來就好多了。代碼更少了,不過我們先來看下這是什么意思。這個forEach方法是一個高階函數,它接收一個lambda表達式或者代碼塊,來對列表中的元素進行操作。在每次調用的時候 ,集合中的元素會綁定到name這個變量上。底層庫托管了lambda表達式調用的活。它可以決定延遲表達式的執(zhí)行,如果合適的話還可以進行并行計算。 這個版本的輸出也和前面的一樣。

復制代碼 代碼如下:

Brian
Nate
Neal
Raju
Sara
Scott

內部迭代器的版本更為簡潔。而且,使用它的話我們可以更專注每個元素的處理操作,而不是怎么去遍歷——這可是聲明式的。

不過這個版本還有缺陷。一旦forEach方法開始執(zhí)行了,不像別的兩個版本,我們沒法跳出這個迭代。(當然有別的方法能搞定這個)。因此,這種寫法在需要對集合里的每個元素處理的時候比較常用。后面我們會介紹到一些別的函數可以讓我們控制循環(huán)的過程。

lambda表達式的標準語法,是把參數放到()里面,提供類型信息并使用逗號分隔參數。Java編譯器為了解放我們,還能自動進行類型推導。不寫類型當然更方便了,工作少了,世界也清靜了。下面是上一個版本去掉了參數類型之后的:

復制代碼 代碼如下:

friends.forEach((name) -> System.out.println(name));

在這個例子里,Java編譯器通過上下文分析,知道name的類型是String。它查看被調用方法forEach的簽名,然后分析參數里的這個函數式接口。接著它會分析這個接口里的抽象方法,查看參數的個數及類型。即便這個lambda表達式接收多個參數,我們也一樣能進行類型推導,不過這樣的話所有參數都不能帶參數類型;在lambda表達式中,參數類型要么全不寫,要寫的話就得全寫。

Java編譯器對單個參數的lambda表達式會進行特殊處理:如果你想進行類型推導的話,參數兩邊的括號可以省略掉。

復制代碼 代碼如下:

friends.forEach(name -> System.out.println(name));

這里有一點小警告:進行類型推導的參數不是final類型的。在前面顯式聲明類型例子中,我們同時也把參數標記為final的。這樣能防止你在lambda表達式中修改參數的值。通常來說,修改參數的值是個壞習慣,這樣容易引起B(yǎng)UG,因此標記成final是個好習慣。不幸的是,如果我們想使用類型推導的話,我們就得自己遵守規(guī)則不要修改參數,因為編譯器可不再為我們保駕護航了。

走到這步可費了老勁了,現在代碼量確實少了一點。不過這還不算最簡。我們來體驗下最后這個極簡版的。

復制代碼 代碼如下:

friends.forEach(System.out::println);

在上面的代碼中我們用到了一個方法引用。我們用方法名就可以直接替換整個的代碼了。在下節(jié)中我們會深入探討下這個,不過現在我們先來回憶下Antoine de Saint-Exupéry的一句名言:完美不是無法再增添加什么,而是無法再去掉什么。

lambda表達式讓我們能夠簡潔明了的進行集合的遍歷。下一節(jié)我們會講到它如何使我們在進行刪除操作和集合轉化的時候,也能夠寫出如此簡潔的代碼。

相關文章

  • Java8中Stream流式操作指南之入門篇

    Java8中Stream流式操作指南之入門篇

    Java8中有兩大最為重要的改變,第一個是Lambda?表達式,另外一個則是Stream?API(java.util.stream.*),下面這篇文章主要給大家介紹了Java8中Stream流式操作指南之入門篇的相關資料,需要的朋友可以參考下
    2022-02-02
  • java必學必會之方法的重載(overload)

    java必學必會之方法的重載(overload)

    java必學必會之方法的重載,介紹了方法的重載、構造方法的重載,想要學好java方法的重載的朋友一定要好好閱讀這篇文章
    2015-12-12
  • SpringBoot中注解@AliasFor的使用詳解

    SpringBoot中注解@AliasFor的使用詳解

    這篇文章主要為大家詳細介紹了SpringBoot中注解@AliasFor的用法,文中的示例代碼講解詳細,對我們學習或工作有一定幫助,需要的可以參考一下
    2022-05-05
  • Java 中實現隨機無重復數字的方法

    Java 中實現隨機無重復數字的方法

    為了更好地理解這個題意,我們先來看下具體內容:生成一個1-100 的隨機數組,但數組中的數字不能重復,即位置是隨機的,但數組元素不能重復
    2013-03-03
  • JAVA 注解詳解及簡單實例

    JAVA 注解詳解及簡單實例

    這篇文章主要介紹了JAVA 注解詳解及簡單實例的相關資料,需要的朋友可以參考下
    2017-05-05
  • springboot2.x只需兩步快速整合log4j2的方法

    springboot2.x只需兩步快速整合log4j2的方法

    這篇文章主要介紹了springboot2.x只需兩步快速整合log4j2的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05
  • 淺析java中print和println的區(qū)別

    淺析java中print和println的區(qū)別

    以下是對java中print和println的區(qū)別進行了詳細的分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • Java?Chassis3熔斷機制的改進路程技術解密

    Java?Chassis3熔斷機制的改進路程技術解密

    這篇文章主要介紹了Java?Chassis?3技術解密之熔斷機制的改進路程實例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • SpringBoot自動重啟的兩種方法

    SpringBoot自動重啟的兩種方法

    我們在項目開發(fā)階段,可能經常會修改代碼,修改完后就要重啟Spring Boot,本文主要介紹了SpringBoot自動重啟的兩種方法,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • Maven本地打包war包實現代碼解析

    Maven本地打包war包實現代碼解析

    這篇文章主要介紹了Maven本地打包war包實現代碼解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09

最新評論