1. ホーム
  2. java

[解決済み] 2つのJava 8ストリーム、または1つのストリームへの追加要素の追加

2022-04-23 05:12:24

質問

このように、ストリームやエクストラエレメントを追加することができます。

Stream stream = Stream.concat(stream1, Stream.concat(stream2, Stream.of(element));

そして、このように新しいものをどんどん追加していくことができるんだ。

Stream stream = Stream.concat(
                       Stream.concat(
                              stream1.filter(x -> x!=0), stream2)
                              .filter(x -> x!=1),
                                  Stream.of(element))
                                  .filter(x -> x!=2);

しかし、これは醜いです、なぜなら concat は静的です。もし concat がインスタンスメソッドであれば、上記の例はもっと読みやすくなるはずです。

 Stream stream = stream1.concat(stream2).concat(element);

そして

 Stream stream = stream1
                 .filter(x -> x!=0)
                 .concat(stream2)
                 .filter(x -> x!=1)
                 .concat(element)
                 .filter(x -> x!=2);

質問です。

1) 何か良い理由はありますか? concat は静的ですか?それとも、私が見逃している同等のインスタンス・メソッドがあるのでしょうか?

2) いずれにせよ、もっと良い方法があるのでしょうか?

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

を追加した場合 静的インポート に対して Stream.concat ストリーム.オブ とすると、最初の例は次のように書くことができる。

Stream<Foo> stream = concat(stream1, concat(stream2, of(element)));

インポート 静的メソッド を一般名で使用すると、読みにくく保守しにくいコードになることがあります ( 名前空間の汚染 ). そのため、独自の 静的メソッド をもっと意味のある名前にしてください。しかし、デモンストレーションのために、この名前にこだわってみます。

public static <T> Stream<T> concat(Stream<? extends T> lhs, Stream<? extends T> rhs) {
    return Stream.concat(lhs, rhs);
}
public static <T> Stream<T> concat(Stream<? extends T> lhs, T rhs) {
    return Stream.concat(lhs, Stream.of(rhs));
}

この2つの静的メソッドを使えば(オプションで静的インポートを組み合わせれば)、2つの例は次のように書けます。

Stream<Foo> stream = concat(stream1, concat(stream2, element));

Stream<Foo> stream = concat(
                         concat(stream1.filter(x -> x!=0), stream2).filter(x -> x!=1),
                         element)
                     .filter(x -> x!=2);

コードが大幅に短くなりました。しかし、読みやすさが向上していないことには同意します。そこで、別の解決策を考えてみました。


いろいろな場面で コレクター を使用することができます。 拡張 ストリームの機能性 つの コレクター を下に置くと、2つの例は次のように書くことができる。

Stream<Foo> stream = stream1.collect(concat(stream2)).collect(concat(element));

Stream<Foo> stream = stream1
                     .filter(x -> x!=0)
                     .collect(concat(stream2))
                     .filter(x -> x!=1)
                     .collect(concat(element))
                     .filter(x -> x!=2);

この構文と上記の構文との唯一の違いは concat(...) collect(concat(...)する) . この2つの静的メソッドは、以下のように実装することができます(オプションで静的インポートとの組み合わせで使用します)。

private static <T,A,R,S> Collector<T,?,S> combine(Collector<T,A,R> collector, Function<? super R, ? extends S> function) {
    return Collector.of(
        collector.supplier(),
        collector.accumulator(),
        collector.combiner(),
        collector.finisher().andThen(function));
}
public static <T> Collector<T,?,Stream<T>> concat(Stream<? extends T> other) {
    return combine(Collectors.toList(),
        list -> Stream.concat(list.stream(), other));
}
public static <T> Collector<T,?,Stream<T>> concat(T element) {
    return concat(Stream.of(element));
}


もちろん、この解決策には言及すべき欠点があります。 集める はストリームの全要素を消費する最終操作です。そのうえで、コレクターが コンカット は中間的な ArrayList は、チェーンで使用されるたびに どちらの操作も、プログラムの動作に大きな影響を与える可能性があります。しかし、もし 可読性 よりも重要です。 性能 しかし、これは非常に有効な方法です。