私のコードには次のような非常に多くのスポットがあります:
_someStream.collect(Collectors.toList())
_
Collectors.toList()
は、使用するたびに新しいコレクターを作成します。
これは、次のようなことが許可されており、推奨されるかどうかという質問につながります:
_private final static Collector<…> TO_LIST = Collectors.toList()
_
私が使用するすべてのタイプに対して、そのような単一のコレクターを使用します:
_someStream.collect(TO_LIST)
_
コレクターが必要な場合。
コレクターはステートレスであり、単なる関数と特性のコレクションであるため、機能するはずですが、OTOH、Collectors.toList()
は呼び出しごとに新しい_CollectorImpl<>
_を作成します。
コレクターを再利用することの欠点は何ですか?
これはstyleの質問に近いと思いますが、考えてみましょう。
つまり、「無駄な」パフォーマンスが心配な場合。ストリームを使用するコードの各行を調べて、そのストリームが「十分な」オブジェクトで機能しているかどうかを判断し、そもそもストリームの使用を正当化する必要があります。これらのストリームにはquite someオーバーヘッドが付いています!
要するに、Javaコミュニティはまだストリームの「標準的なベストプラクティス」を見つけていないため、現時点では私の(個人的な)2セント:「全員」が使用しているパターンを好む-避ける特に「パフォーマンス関連」である場合。
Collector
は基本的に4つの関数と特性フラグのコンテナであるため、再利用しても問題はありませんが、メモリ管理に対するこのような軽量オブジェクトの影響は無視できるとしても無視できるため、利点はほとんどありませんとにかくオプティマイザーによって完全に削除されました。
組み込みのCollector
で見られるように、Collectors
sを再利用しない主な理由は、タイプセーフな方法でそれを実行できないことです。任意の型のList
sのコレクターを提供する場合、常に同じCollector
インスタンスを配布するために未チェックの操作が必要になります。代わりにCollector
を適切に型付けされた変数に保存し、未チェックの操作なしで使用する場合は、List
sの1つのタイプにのみ使用でき、その例にとどまります。
Collections.emptyList()
などの場合、JRE開発者は別の方法を使いましたが、定数EMPTY_LIST
、EMPTY_MAP
、EMPTY_SET
はジェネリックの導入前にすでに存在しており、30個以上の組み込みコレクターのうち4つの特別なケースであるいくつかのキャッシュ可能なCollectors
よりも汎用性が高いと思います。関数パラメーターのためにキャッシュされます。関数パラメーターはラムダ式を介して実装されることが多く、不特定の同一性/等価性のオブジェクトを生成するため、それらをコレクターインスタンスにマッピングするキャッシュは予測不可能な効率を持ちますが、メモリマネージャーが一時インスタンスを処理するよりもはるかに効率が低い可能性が非常に高くなります。
ライブラリが有用なオブジェクトを取得するためにfactory methodを提供することは良い習慣です。ライブラリが提供されているメソッド:Collectors.toList()
であるため、ライブラリを改ざんする代わりに、オブジェクトが要求されるたびに新しいインスタンスを作成するかどうかをライブラリに決定させます.
これは、GhostCatとHolgerの回答に、支持的な議論として追加される:)
@Holgerがオプティマイザーがスマートであり、その構造を完全に置き換えることについての彼の答えで言っていることは、ほんの小さな補足です。それはscalar replacement
と呼ばれます。メソッド内で使用されるオブジェクトがde-constructedであり、そのフィールドがstack allocated like normal local variables
である場合。そのため、結果のCollector
は、JVMレベルでオブジェクト自体として扱われない場合があります。それはJIT time
で起こります。
単一の静的オブジェクトを使用して、オンザフライで作成されたオブジェクトの代わりになるという古典的な問題は、可変性です。 Java 8ソースのクイックスキャンは、Set<Characteristics>
フィールドは問題の可能性があります。
明らかに、どこかのコードで次のようなことをすることが可能です。
private final static Collector<Object, ?, List<Object>> TO_LIST = Collectors.toList();
public void test() {
// Any method could do this (no idea why but it should be possible).
TO_LIST.characteristics().add(Collector.Characteristics.IDENTITY_FINISH);
}
このcouldはeveryの使用をグローバルに変更しますTO_LIST
これは非常に不明瞭なバグを作成する可能性があります。
だから私見-しないでください!
これは、時期尚早な最適化の場合です。オブジェクトの作成は非常に安価です。通常のラップトップでは、1秒あたり10M〜50Mのオブジェクトを作成できると予想されます。これらの数値を念頭に置いて、演習全体が無意味になります。