2017-04-17 86 views
1

我知道我們不能實例化一個接口,但是在做關於Streams的書的教程時,我感到困惑。當它說接口的方法返回什麼時,API是什麼意思?

我只是用部分代碼來突出顯示我不明白的部分。

// count occurences of each word in a Stream<String> sorted by word 
    Map<String, Long> wordCounts = 
     Files.lines(Paths.get("Chapter2Paragraph.txt")) 
      .map(line -> line.replaceAll("(?!')\\p{P}", "")) 
      .flatMap(line -> pattern.splitAsStream(line)) 
      .collect(Collectors.groupingBy(String::toLowerCase, 
       TreeMap::new, Collectors.counting())); 

對於該方法flatMap,當在所述API在點擊時,它說:

返回由與映射流的內容替換該流中的每個元素的結果的流通過將所提供的映射函數應用於每個元素而產生。每個映射流都將其內容放入此流後關閉。 (如果映射流爲空,則使用空流,而不是。)

那麼它是什麼意思?我有點明白它的作用,但我根本不明白它是如何在幕後工作的。在這種情況下API提到返回時是否返回一個對象,還是這意味着它會替換當前流?此外,使用Streams時,編譯器是否實際創建了這些元素的Object,然後在完成時終止?

此外,從上面的代碼,我只是想確保我是正確的。 當你有一個Map<String, Long> wordCounts變量時,這是否意味着在流終止時,最終結果必須嚴格遵循類型推斷?

+1

你在問這些文檔是什麼意思,或者它在幕後做了什麼?因爲這是兩個近乎正交的問題。 –

+1

閱讀這個問題,我很高興在移動到Java版本8之前學習了Python生成器。 –

+0

@MadPhysicist我想知道幕後發生了什麼,在嘗試任何操作之前先學習Python更好其他語言爲了更好地理解? – Scorpiorian83

回答

1

您似乎已經大致正確地分析了這種情況,但也許您對某些中間步驟感到朦朧。

您有一系列方法在鏈中前一個方法的返回值上調用。最終方法(collect)的返回值存儲在名爲wordCountsMap中。無視這些方法到底做了些什麼以及它們返回的內容(只是暫時的),當你調用這樣的方法鏈時,這是標準行爲。

地圖的一般類型由最終方法調用中的String::toLowerCaseCollectors.counting()決定。前者指定密鑰類型爲String,後者指定值爲Long。例如,如果您使用String::length作爲關鍵字,那麼您應該得到一個類型爲Map<Integer, Long>的地圖,它將計算具有給定長度的單詞的出現次數。

讓我們回到函數調用的順序,可以細分如下:

  1. Files.lines(Path)創建一個文件中的行的Stream<String>。由於結果是流,因此您現在可以調用...
  2. Stream.map(Function<String, String>)使用調用line.replaceAll(...)將字符串的輸入流轉換爲另一個字符串流。
  3. 編輯行流現在得到Stream.flatMap(Function<String, Stream<String>>)它將行分成單詞並返回一個連續的流。請記住,pattern.splitAsStream將按順序應用於每條線,因此會返回與線條一樣多的流。 Stream.flatMap接收所有這些流並將它們串聯到一個連續的流中。

    請注意,封裝的全部目的是您不必知道引擎蓋下的過程是如何工作的。你只需要知道最終結果是什麼(在這種情況下是Stream<String>)。您應該能夠將預先讀取所有流的實現交換爲基礎集合,並從中返回一個流,其中一個會在處理元素時懶散地打開每個流,而不必擔心實際發生的情況。

  4. 現在您已在文件中有一個Stream<String>字詞,您可以應用所謂的終端操作:Stream.collect(Collector<String, String, Map<String, Long>>)。收藏家由Collectors.groupingBy(Function<String, String>, Supplier<Map<String, String>>, Collector<String, String, Long>)創建。這創建了一個收集器,該收集器根據分類器FunctionString.toLowerCase())返回的密鑰將輸入流分組爲子流,並將其傳遞到「下游」收集器,以在每個子流上進行實際的累加。產生的積累存儲在由SupplierTreeMap::new)返回的映射中。下游CollectorCollectors.counting()創建,它只計算每個流中元素的數量。

我已經擴展了本說明中的所有泛型,使其更容易遵循,並查看每步產生的對象種類。

在更一般的說明中,Java中的流有兩種類型的操作:intermediate和terminal。流來源(在這種情況下,你的文件)。所有中間操作(1-3)將一個流轉換爲另一個流。正如我上面所示,輸入和輸出類型總是明確定義的,就像其他任何操作一樣。終端操作是基於流返回某種類型的單個值的操作。在你的情況下,你可以統計單詞頻率並將它們存儲到Map中。這在java.util.stream package summary中有很好的記錄。

2

flapMap()將每個元素轉換爲任何類型的流。溪流串聯在一起形成一條大溪流。

在您的示例中,整個文件在模式上分割每行(在問題中未指定)之後進行流式傳輸(作爲一個流)。

相關問題