Javaの8シーケンシャルストリームの任意の直接的または間接的なパフォーマンス上のメリットはありますか?

Hitesh:

ループやストリームの伝統の上に、順次ストリームを使用して、任意のパフォーマンス上の利点は、追加のパフォーマンス・オーバーヘッドでちょうどシーケンシャル糖衣構文シーケンシャルストリームの記事を通過しながら、疑問が私の心に来ましたがされていること?

私はシーケンシャルストリームを使用して、任意のパフォーマンス上の利点を見ることができない以下の実施例を検討:

Stream.of("d2", "a2", "b1", "b3", "c")
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("a");
})
    .forEach(s -> System.out.println("forEach: " + s));

古典的なJavaを使用して:

String[] strings = {"d2", "a2", "b1", "b3", "c"};
        for (String s : strings)
        {
            System.out.println("Before filtering: " + s);
            if (s.startsWith("a"))
            {
                System.out.println("After Filtering: " + s);
            }
        }

ポイントはここD2上のすべての操作が完了した後にのみa2の開始の処理の流れである(以前の私は、d2はforeachのことで処理されている間、フィルタはA2上で動作stratedているだろうと思ったが、それは、この記事ごとのように、ケースではありません:HTTPS: //winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/)、同じことがコーディングだから何が「表現力」と「エレガント」を超えてストリームを使用しての動機である必要があり、従来のJavaの場合でありますストリームを処理しながら、順次ストリームを使用しながら、スタイル?私はパフォーマンスのオーバーヘッドは、コンパイラのためにそこにいることを知っている、誰もが知っている/任意のパフォーマンス上の利点について経験しているのでしょうか?

ホルガー:

まず、冗長省略するように、特別なケースをさせるsorted操作をまたは上の既知のサイズを返すcount()実行タイミングのすべての違いは、一定のオフセットかについて通常あるので、さておき、操作の時間計算量は、通常、むしろ(、変更されません。小)要因ではなく、根本的な変化。


ストリームの実装が内部的に行うようにいつでも基本的に同じことをやって、マニュアルループを書くことができます。だから、で述べたように内部の最適化、この答えはいつも「私は私のループ内で同じことを行うことができます」と退け取得できます。

私たちは、「ループ」と「ストリーム」を比較する場合でも...、それはすべての手動ループは、特定のユースケースのために最も効率的な方法で書かれていると仮定するのは本当に合理的ですか?該当する場合、特定のストリームの実装では、呼び出し元のコードの作者の経験レベルに関係なく、すべてのユースケースへの最適化を適用します。私はすでに短絡する機会を逃したり、特定のユースケースに必要のない冗長な操作を実行するループを見てきました。

別の態様は、特定の最適化を実行するために必要な情報です。ストリームAPIを中心に構築されSpliteratorたソースデータの特性を提供できるインタフェース、例えばそれは、データが特定の操作のためか、すでに事前にソートされているかどうかを保持するために必要な、意味のある順序を持っているかどうかを自然な順序に、見つけることができますまたは特定のコンパレータと。また、推定又は正確な、予測可能な場合として、要素数の期待値を提供することができます。

任意の受信方法はCollection、通常のループを有するアルゴリズムを実装するために、そのような特性があるかどうか、見つけるのに苦労しなければなりません。AはListに対し、意味のある順序を意味しSet、それはいない限り、通常、しないSortedSetか、LinkedHashSet後者はむしろ界面よりも、特定の実装クラスであるのに対し、。だから、事前に定義されたインタフェースによって表現できない特別な契約を結んでいるかもしれない、まだミスサードパーティの実装では、すべての既知の星座に対してテストします。

もちろん、Javaの8以来、あなたが取得することができSpliterator、自分でこれらの特性を調べるために、それは非自明なものにあなたのループソリューションを変更しても、すでにストリームAPIで行われた作業を繰り返し暗示します。


間に別の興味深い違いもありますSpliteratorベースのストリーム・ソリューションと従来のループが使用して、Iterator配列以外の繰り返し処理を行う場合。パターンは呼び出すことがあるhasNextが続き、イテレータでnextない限り、hasNext返されましたfalseしかし、契約は、Iteratorこのパターンを強制しません。呼び出し側は、呼び出すことがnextなくてhasNext、(例えば、あなたが既にコレクションのサイズを知っていますか)成功することが知られているとき、あっても複数回。また、呼び出し側は、呼び出してもよいhasNextことなく、複数回next呼び出し側が前の呼び出しの結果を覚えていなかった場合には。

その結果、Iterator実装は、例えばループ条件が効果的では1回、2回チェックされている冗長な操作を実行する必要がありhasNext、戻るにはboolean、とに一度next、スローするようにNoSuchElementException満たされていないとき。多くの場合、hasNext実際のトラバーサル操作を実行し、に結果を格納するために持っているIterator結果が、後続まで有効のままことを保証するために、インスタンスnextの呼び出し。nextターンでの動作は、そのようなトラバースが既に起こるか、それは操作自体を実行するために持っているかどうかなかったかどうかを確認する必要があります。実際には、ホットスポットオプティマイザは、またはによって課されるオーバーヘッド排除しない場合がありますIteratorデザインを。

対照的に、Spliterator単一のトラバーサル方法有するboolean tryAdvance(Consumer<? super T> action)実際の動作行い、及び要素があったかどうかを返しています。これは、大幅にループロジックを簡素化します。そこでもだvoid forEachRemaining(Consumer<? super T> action)非短絡操作のため、ロジックをループ全体を提供するために、実際の実装を可能にします。例えば、の場合にArrayList動作普通アレイへのアクセスを行う、インデックス上の単純な計数ループで終わるであろう。

あなたはこのような設計、例えば比較することができるreadLine()BufferedReader操作とリターンを行い、null最後の要素の後に、またはfind()正規表現のMatcher検索を行い、正規表現エンジンの状態を返す成功状態を更新します。

しかし、このような設計の違いの影響は、冗長な操作を識別し、排除するために特別に設計オプティマイザと環境に予測することは困難です。お持ち帰りは、それが今までに特定のシナリオに実体化するかどうかを多くの要因に依存しながら、さらに高速であることが判明するストリームベースのソリューションのためのいくつかの可能性があるということです。冒頭で述べたように、それは通常、心配することはより重要になり、全体の時間の複雑さを、変更していません。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=99165&siteId=1