1. ホーム
  2. java

[解決済み] ストリームはいつ使うべきですか?

2022-10-23 01:13:36

質問

を使用する際に疑問に思ったことがあります。 List とその stream() というメソッドがあります。私が知っている間は どのように を使うことは知っていますが、を使うことについてはよく分かっていません。 いつ についてはよくわかりません。

例えば、異なる場所への様々なパスを含むリストがあるとします。今、私は、単一の与えられたパスがリストで指定されたパスのいずれかを含むかどうかをチェックしたいと思います。私は boolean を返したい。

もちろん、これ自体は難しいことではありません。しかし、ストリームを使うべきか、それともfor(-each)ループを使うべきか、悩ましいところです。

リスト

private static final List<String> EXCLUDE_PATHS = Arrays.asList(
    "my/path/one",
    "my/path/two"
);

Streamを使った例。

private boolean isExcluded(String path) {
    return EXCLUDE_PATHS.stream()
                        .map(String::toLowerCase)
                        .filter(path::contains)
                        .collect(Collectors.toList())
                        .size() > 0;
}

for-eachループを使った例。

private boolean isExcluded(String path){
    for (String excludePath : EXCLUDE_PATHS) {
        if (path.contains(excludePath.toLowerCase())) {
            return true;
        }
    }
    return false;
}

なお path パラメータは常に 小文字 .

最初に推測したのは、条件が満たされたらループがすぐに戻るので、for-each アプローチの方が速いということです。一方、ストリームはフィルタリングを完了するために、すべてのリスト エントリに対してまだループします。

私の推測は正しいでしょうか。もしそうなら なぜ (あるいはむしろ いつ を使うか? stream() を使うのでしょうか?

どのように解決するのですか?

あなたの仮定は正しいです。ストリームの実装は、for-loopより遅いです。

このストリームの使い方は、for-loopと同じくらい速いはずですが。

EXCLUDE_PATHS.stream()  
    .map(String::toLowerCase)
    .anyMatch(path::contains);

これは、項目を繰り返し、 String::toLowerCase とフィルタを一個一個適用し で終了し、最初の項目 で終了します。

どちらも collect() & anyMatch() は端末操作です。 anyMatch() は最初に見つかった項目で終了しますが、一方 collect() は全ての項目を処理することを要求しています。