2017-05-30 5 views
3

私はいくつかの苦情をすることを許可してください、たぶんそれは退屈ですが、私は説明したい: "この質問はなぜ起きましたか?"。 昨夜、質問に答えた人はhereherehereです。 JDK-9と.etcでStream#map & Collectors#mappingStream#filter & Collectors#filtering:私はそれを掘り下げる取得した後ストリーム操作がコレクタと重複しているのはなぜですか?

は、私がStreamDon't repeat yourself原則に違反しCollector、例えば間に多くの重複のロジックがある見つけました。

しかしStreamTell, Don't ask原則/ Law of Demeterを順守し、CollectorComposition over Inheritance原則を順守するので、それは合理的に思えます。

私だけStream操作がCollector秒以下のようにして複製され、いくつかの理由を考えることができます。

  1. 我々はStreamが大きなコンテキストで作成されたかを気にしません。それは例えば、単に別のStreamStreamをマッピングすることができるので、この場合にStream動作をより効果的かつ迅速Collectorより:

    consuming(stream.map(...)); 
    consuming(stream.collect(mapping(...,toList())).stream()); 
    
    void consuming(Stream<?> stream){...} 
    
  2. Collector缶は、ストリーム内の要素を収集するCollectorが一緒だ構成がより強力ですしかしながら、Streamは、いくつかの有用な/高度に使用される操作しか提供していない。例えば:いくつかの単純な作業を行うとき

    stream.collect(groupingBy(
        ..., mapping(
         ..., collectingAndThen(reducing(...), ...) 
         ) 
    )); 
    
  3. Stream操作がCollectorよりも表現力であるが、それは、各操作のための新しいストリームを作成し、Streamがより重く、抽象的であるため、彼らはCollector秒より遅いですCollector。例えば:

    stream.map(...).collect(collector); 
    stream.collect(mapping(..., collector)); 
    
  4. CollectorStreamとして短絡端子操作を適用することはできません。例えば:ストリームの操作はここではコレクターで複製され、なぜ誰もが、他の欠点/利点と

    stream.filter(...).findFirst(); 
    

まで来ることができていますか?私はそれらを再理解したいと思います。前もって感謝します。

+0

それは彼らがそれを設計した方法なので。苦情があった場合は、バグ報告や改善依頼を提出するか、ホールを雇う。 – EJP

+3

も参照してください。[Collectors.summingInt()vs mapToInt().sum()](https://stackoverflow.com/q/37023822/2711488) – Holger

+0

@Holgerリンクのおかげで、私はほとんどの時間を要する私は英語が上手ではないので、あなたのものです。 –

答えて

7

専用ターミナルストリーム操作をチェインすると、作成されたコレクタファクトリコールの "LISPスタイル"ではなく、メソッド呼び出しの連鎖に使用されている人がより表現力があると考えられます。しかし、ストリーム実装のための最適化された実行ストラテジも可能です。これは、抽象度がCollectorである代わりに、実際の操作を知っているためです。

一方、自分で名前を付けたように、Collectorを作成して、ストリーム操作がもう不可能な場所で別のコレクタに埋め込まれたこれらの操作を実行できるようにします。このミラーリングは、Java 8の開発の後半にのみ明らかになります。これは、filteringまたはflatMappingのような対応がない操作がJava 9にのみ存在する理由です。したがって、2つの異なるAPI同様のことは、開発の開始時に行われた設計上の決定ではありませんでした。

+2

私は「LISPスタイル」が不合理であるとは言いませんでした。私が言ったのは、Java開発者は連鎖呼び出しスタイルに慣れているということです。 – Holger

+0

ありがとうございました。 –

+1

@Holgerもしあなたが正しければ、java-8がどれぐらい遅れていたのかを考えれば、これは完璧な意味があります... – Eugene

6

の方法を複製しているように見える方法は、追加機能を提供しています。それらは他のCollectorと組み合わせて使用​​すると意味があります。

たとえば、Collectors.mapping()と考えると、最も一般的な使用方法はCollectors.groupingByCollectorに渡すことです。

は(のJavadocから引用)この例を考える:

List<Person> people = ... 
Map<City, Set<String>> namesByCity 
     = people.stream().collect(groupingBy(Person::getCity, TreeMap::new, 
               mapping(Person::getLastName, toSet()))); 

mappingStringPersonから各グループの値Collectionの要素タイプを変換するためにここで使用されます。

なし(およびtoSet()Collector)の出力はMap<City, List<Person>>になります。

さて、あなたは確かにmapStream<Person>からStream<String>people.stream().map(Person::getLastName)を使用することができますが、あなたは(この例では、Person::getCityPersonの他のいくつかのプロパティによってグループにこれらの最後の名前を能力を失うことになります。

+0

先生、ありがとう。私は私の質問で2番目にそれを記述していることが分かった。しかし、私は広すぎます。 –

関連する問題