ストリームとラムダに関するJava-8の話題を調べ始めるのに少し時間がかかりました。私が驚いたのは、.map()
、.filter()
などのストリーム操作を_Java.util.Collection
_に直接適用できないことです。 _Java.util.Collection
_インターフェイスがこれらのストリーム操作のデフォルトの実装で拡張されなかった技術的な理由はありますか?
少しグーグルすると、次のパターンに沿ってコーディングしている人々の例がたくさんあります。
_List<String> list = someListExpression;
List<String> anotherList = list.stream().map(x -> f(x)).collect(Collectors.toList());
_
コードにこれらのストリーム操作がたくさんある場合、これは非常に不器用になります。 .stream()
と.collect()
は表現したい内容とはまったく関係がないので、次のように言います。
_List<String> list = someListExpression;
List<String> anotherList = list.map(x -> f(x));
_
はい、これらの決定には優れた理由があります:)
重要なのは、eager操作とlazy操作の違いです。最初の質問で示した例は、リストをマッピングまたはフィルタリングすると新しいリストが生成される熱心な操作を示しています。これには何の問題もありませんが、多くの場合、必要以上の作業を行っているため、必要なものではありません。熱心な操作はすべての要素で動作し、新しいコレクションを生成する必要があります。複数の操作(filter-map-reduce)を作成している場合は、多くの余分な作業を行っています。一方、怠惰な操作は美しく構成されます。もしあなたがそうするなら:
_Optional<Person> tallestGuy = people.stream()
.filter(p -> p.getGender() == MALE)
.max(comparing(Person::getHeight));
_
フィルタと削減(最大)操作は、1つのパスに融合されます。これは非常に効率的です。
では、Streamメソッドをリストに公開してみませんか?そうですね、そうやってみました。他の多くの理由の中で、filter()
のような怠惰なメソッドとremoveAll()
のような熱心なメソッドを混在させることはユーザーを混乱させることがわかりました。怠惰なメソッドを個別の抽象化にグループ化することにより、それははるかに明確になります。 List
のメソッドは、リストを変更するメソッドです。 Stream
のメソッドは、データがどこにあるかに関係なく、データシーケンスに対する構成可能な遅延操作を処理するメソッドです。
ですから、あなたが提案する方法は、本当に単純なことをしたいのであれば素晴らしいのですが、それを基に構築しようとすると崩壊し始めます。余分なstream()
メソッドは煩わしいですか?承知しました。ただし、データ構造(主にメモリ内のデータの整理に関するもの)とストリーム(主に集計動作の構成に関するもの)の抽象化を維持することで、より高度な操作に適したスケールになります。
2番目の質問に対して、これは比較的簡単に実行できます。次のようなストリームメソッドを実装します。
_public<U> Stream<U> map(Function<T,U> mapper) { return convertToStream().map(mapper); }
_
しかし、それはただ潮に逆らって泳いでいるだけです。効率的なstream()メソッドを実装する方が良いでしょう。