「Java 8 函數式編程」讀書筆記——流

本文是「Java 8 函數式編程」第三章的讀書筆記,章名爲流。本章主要介紹了外部迭代與內部迭代以及經常使用的高階函數。java

外部迭代與內部迭代

外部迭代

過去咱們要對一個List進行迭代時,每每會採用以下方式:編程

int count = 0;
for (Artist artist : artists) {
  if (artist.isFrom("London")) {
    count++;
  }
}

而這種方法的原理,實際上是先調用iterator方法,而後再迭代,等效於以下代碼:數組

int count = 0;
Iterator<Artist> iterator = artists.iterator();
while (iterator.hasNext()) {
  Artist artist = iterator.next();
  if (artist.isFrom("London")) {
    count++;
  }
}

這樣的迭代方式,把迭代的控制權交給了iterator對象,讓其控制整個迭代過程,這就叫作外部迭代數據結構

外部迭代須要咱們本身編寫迭代的控制代碼,顯得十分繁瑣。特別是對於Map對象,繁瑣到我都不想給出例子。框架

外部迭代將行爲和方法混爲一談,難以對代碼進行重構操做。函數式編程

內部迭代

與之相對的就是內部迭代了。內部迭代就是把迭代的控制權交給了集合自己,讓集合本身實現相應的迭代,而調用者並不須要關心如何迭代函數

要使用內部迭代,須要使用Java 8中新增的接口Stream。而集合框架都已經包含了一個stream()方法,用於得到Stream對象。oop

long count = artists.stream()
  .filter(artist -> artist.isFrom("London"))
  .count();

這個例子就是使用的內部迭代。先獲取stream對象,而後調用filter方法過濾,最後統計符合條件的個數。優化

實現機制

Java中調用一個方法,一般會當即執行操做。然而Stream裏的一些方法卻不太同樣,它們返回的對象不是新的集合,而是建立新集合的配方。咱們經過一個例子說明:spa

Stream<String> names = Stream.of("Bryant", "Jordon", "James")
  .filter(name -> {
    System.out.println(name);
    return name.length() == 6;
  });
System.out.println("counting");
System.out.println(names.count());

最終會獲得以下輸出:

counting
Bryant
Jordon
James
2

出現這樣的結果,緣由是

  • filter這樣的方法,只會描述Stream,最終不會產生新集合的方法叫作惰性求值方法

  • count這樣會從Stream中產生值或集合等結果的方法叫作及早求值方法

判斷一個操做是惰性求值仍是及早求值,只須要看它的返回值

  • 若是返回值是Stream,則是惰性求值

  • 返回的是一個值或null,則是及早求值

在對集合使用流操做時,使用惰性求值方法造成一個惰性求值的鏈,最後用及早求值方法獲得結果,而集合只須要迭代一次。

經常使用流操做

  • collect:及早求值,經常使用於生成List Map或其餘複雜的數據結構

  • map:惰性求值,將一種類型的數據轉換成另外一種類型,將一個流中的值轉化成一個新的流,相似於Hadoop裏的map

  • filter:惰性求值,過濾不符合條件的元素

  • flatMap:惰性求值,相似於map,只是Function參數的返回值限定爲Stream,用於鏈接多個Stream成爲一個Stream

  • max & min:及早求值,reduce方法的特例,返回Optional(第四章介紹)對象

  • reduce:及早求值,從一組值中生成一個值,相似於Hadoop中的reduce

高階函數

高階函數接收一個函數做爲參數,或者返回一個函數的函數。

正確使用Lambda表達式

  • 明確要達成什麼轉化,而不是說明如何轉化

  • 沒有反作用:

    • 只經過函數的返回值就能充分理解函數的所有做用

    • 函數不會修改程序或外界的狀態

    • 獲取值而不是變量(避免使用數組逃過JVM的追殺,應該考慮優化邏輯)

相關文章
相關標籤/搜索