誰かが主なリストのサブリストを返すことによって、次のコードがストリーム版でより高速である理由を私に説明できますか?なぜストリームを単にサブリストを返す反復コードより速くフィルタリングするのですか?
public static final int N = 50000000;
static List<Integer> sourceList = new ArrayList<>();
static {
for (int i = 0; i < N; i++) {
sourceList.add(i);
}
}
@Benchmark
public List<Pair<Integer, Integer>> vanilla() {
List<Pair<Integer, Integer>> collect1 =
sourceList.stream()
.map(integer -> Pair.of(integer, integer))
.collect(Collectors.toList());
return collect1.subList(1000, 100000);
}
@Benchmark
public List<Pair<Integer, Integer>> stream() {
return sourceList.stream()
.map(value -> Pair.of(value, value))
.filter(value -> value.getLeft() > 1000 && value.getLeft() < 100000)
.collect(Collectors.toList());
}
Benchmark Mode Cnt Score Error Units
Test.stream avgt 20 9.867 ± 0.218 ns/op
Test.vanilla avgt 20 183.304 ± 8.550 ns/op
私はJMHを使用してテストを実行しますが、結果はわかりません。私は、ペアにInteger値をラップするマッピング関数を追加することで、ストリームをすべての新しいオブジェクトを作成してフィルタメソッドに渡し、比較のためにペアの左部分を抽出するように強制すると考えました。それはフィルタリングがない他のアプローチよりも私にはもっと集中的に聞こえ、その結果は元のリストのサブリストに過ぎず、したがってリスト全体を通ることはありません。
ここに何か不足していますか?
わかりました。最初にフィルタリングする方が高速ですが、この例のプロダクションコードを単純化しようとしました。プロダクションコードはここでは好きなように、各オブジェクトにint値を代入して与えられたものだけを保持しなければなりません。問題は、カウンタを何とかしておき、オブジェクトがここのようなintではないのでフィルタに渡す必要があることです。このサンプルコードをリファクタリングして、マッピング関数とフィルタ関数を逆にしながらその意味を保持する方法はありますか? – Kilian
あなたが掲示した例の最初のフィルタリングは簡単ですね。あなたの実際の生産コードについては、私はそれを見ずにはできません。 –