2017-04-17 8 views
1

私はインタフェースをインスタンス化することはできませんが、Streamsに関する本からチュートリアルを行っているうちに、私は混乱しました。インターフェイスのメソッドが何かを返すとAPIが意味することは何ですか?

私は理解できない部分を強調するコードの部分を使用します。

は、マッピングされたストリームの内容で、このストリームの各要素を置き換えるの結果からなるストリームを返します:方法flatMap、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())); 

提供されたマッピング関数を各要素に適用することによって生成される。マップされた各ストリームは、その内容がこのストリームに配置された後に閉じられます。マッピングされたストリームがnullの場合、代わりに空のストリームが使用されます。

それで、それはどういう意味ですか?私はそれが何をしているのかちょっと理解していますが、私はそれがどのように裏で働くのか分かりません。 APIがこのケースで返答するとオブジェクトを返すか、それとも現在のストリームを置き換えることを意味しますか?さらに、Streamsを使用している場合、コンパイラは実際にこれらの要素のオブジェクトを作成し、完了したら終了しますか?

さらに、上記のコードから、私が正しいことを確認したいだけです。 Map<String, Long> wordCounts変数を使用している場合、ストリームの終了時に最終結果が型推論に正確に従わなければならないことを意味しますか?

+1

あなたはドキュメントの意味を聞いていますか、それとも舞台裏で何をしていますか?それらは2つのほぼ直交した質問です。 –

+1

この質問を読んで、私はJavaバージョン8に移行する前に、Pythonジェネレータについて勉強したことをうれしく思います。 –

+0

@MadPhysicist何が起こっているのかを知りたいのですが、他の言語をよりよく理解するために? – Scorpiorian83

答えて

1

あなたは状況をほとんど正確に分析しているようですが、中間ステップのいくつかについてはあまり混乱していない可能性があります。

チェーン内の以前のメソッドの戻り値で呼び出される一連のメソッドがあります。最終メソッド(collect)の戻り値は、wordCountsという名前のMapに格納されています。メソッドが何を返すのか、何が返されるのかを無視すると、そのようなメソッドの連鎖を呼び出すと、これは標準的な動作です。

最後のメソッド呼び出しでは、マップの汎用タイプは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. 編集された行のストリームは、その行を単語に分割して1つの連続したストリームを返すようになり、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のストリームには、中間と端末の2種類の操作があります。ストリームはソース(この場合はファイル)から取り出されます。すべての中間操作(1〜3)は、1つのストリームを別のストリームに変換します。上に示したように、他の操作と同様に、入力と出力の型は常に明確に定義されています。ターミナル操作は、ストリームに基づいて何らかの並べ替えの単一の値を返す操作です。あなたの場合は、単語の頻度を数えて、Mapに入れます。これは、java.util.stream package summaryによく書かれています。

2

flapMap()は、各要素を(任意の種類の)ストリームに変換します。ストリームは連結されて1つの大きなストリームになります。

例では、各ファイルがパターン上で分割された後(質問に指定されていない)、ファイル全体が(1つのストリームとして)ストリーミングされます。

関連する問題