java - concat - 將兩個Java 8流或一個額外的元素添加到流中

97 5

我可以添加流或額外的元素,如下所示:


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 是 static 。 如果 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 是 static的原因? 還是有一些等價的實例方法我丟失了?

2 ) 在任何情況下,都是否有更好的方法進行這裡操作?

时间: 原作者:

105 3

如果你添加 static 導入 Stream.concat 和 Stream.of,第一個示例可以如下所示:


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



導入具有通用名稱的static 方法可能會導致難以讀取和維護( 命名空間污染 )的代碼。 因此,最好創建你自己的static 方法,以更有意義的名稱命名。 不過,為了演示,我將堅持這個名稱。


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));


}



使用這兩個 static 方法( 可以選擇與 static 導入組合),可以按如下方式編寫兩個示例:


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);



現在代碼明顯縮短。 然而,我認為可讀性並沒有提高。 所以我有另一個解決方案。

在許多情況下,收集器可以用來擴展擴展流的功能。 下面是兩個收集器在底部,可以編寫如下示例:


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 collect collect collect concat(...) 。 這兩個靜態方法可以實現如下(可選擇與靜態導入結合使用):


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));


}



當然,這個解決方案有一個缺點應該被提及。 collect是一個消耗流的所有元素的最終操作。 此外,收集器 concat在鏈中每次使用時創建一個中間的 。 這兩個操作都會對程序的行為產生重大影響。 然而,如果可讀性比性能更重要,它仍然是一種非常有用的方法。

原作者:
97 4

不幸的是,這個答案可能很少或沒有任何幫助,但我對Java Lambda郵件列表進行了取證分析,看看我是否能找到這種設計的原因。 這是我發現的辦法:

開始的有一個實例方法用於 Stream.concat(Stream)

在郵件列表中,我可以清楚地看到該方法最初是作為實例方法實現的,正如您可以閱讀Paul Sandoz在此主題中關於concat操作的內容。

在其中,他們討論了流可能無限的情況以及在這些情況下串聯意味著什麼的問題,但我不認為這是修改的原因。

您在另一個帖子中看到JDK 8的一些早期用戶在使用null參數時詢問了concat實例方法的行為。

但是,這個它的他線程,顯示,該方法的設計正在討論中。

向 Streams.concat(Stream,Stream) 重構了

但是,沒有任何解釋,突然,這個方法變成了 static 方法,就像你在中看到的,這個線程關於組合流。 這可能是唯一能夠揭示這一變化的郵件帖子,但對於我來說,確定重構的原因尚不清楚。 但是我們可以看到他們提交他們建議將 concat 方法移到 Stream 中,並進入 helper 類 Streams

向 Stream.concat(Stream,Stream) 重構了

後來,再次從移動到 Stream,但是又沒有解釋。

所以,底線,設計的原因對我來說並不完全清楚,我找不到一個好的解釋。 我想你還是可以在郵件列表中提問。

為流連接 Alternatives

Michael Hixson的其他線程討論/詢問關於合併/concat流的其他方法

要合併兩個流,我應該這樣做:


Stream.concat(s1, s2)



不是這樣的:


Stream.of(s1, s2).flatMap(x -> x)



。正確?

要合併兩個上的流,我應該這樣做:


Stream.of(s1, s2, s3,.. .).flatMap(x -> x)



不是這樣的:


Stream.of(s1, s2, s3,.. .).reduce(Stream.empty(), Stream::concat)



。正確?

...