2017-07-28 48 views
6

我需要一個與Collectors.toSet()幾乎相同的收集器,但帶有自定義裝訂器。我希望能夠做到這樣的事情:擴展現有的流收集器實例

myCollector = Collectors.toSet(); 
myCollector.setFinisher(myCustomFinisher); 

並且完成,但這似乎不可能。我能看到的唯一選擇是使用Collector.of()重新創建Collectors.toSet(),這不是非常乾燥。

有沒有辦法讓現有的收藏家和修正如上所述?

編輯

幾個問題的答案都建議是這樣的:

Collector<T, ?, Set<T>> toSet = Collectors.toSet(); 
    return Collector.of(
    toSet.supplier(), 
    toSet.accumulator(), 
    toSet.combiner(), 
    yourFinisher, 
    toSet.characteristics()); 

但是我的自定義整理實際上沒有返回集;它使用累積集合來返回其他內容。它在做的事實把我變成泛型地獄我還在翻箱倒櫃..

+0

這不是最理想的解決方案,但是你可以爲'Collectors'創建一個包裝類,在那裏你可以實現'setFinisher' –

回答

4

這是一個基本toSet實施:

Collector.of(
      HashSet::new, 
      Set::add, 
      (left, right) -> { 
       left.addAll(right); 
       return left; 
      }); 

所有您需要做的就是添加UNORDERED特點和你的終結者。說實話,看起來相當微不足道。 看看Holger的回答。

3

以你的問題的標題從字面上看,你不能達到你想要什麼樣的「擴展」一個Collector返回一個Set,因爲第三泛型類型Collector的參數指定「縮減操作的結果類型」,因此Collector<?,?,R>永遠不可能是Collector<?,?,Set>的子類,除非R實現Set

我不知道你想用Set作爲終飾功能,我也不知道你的Set中的元素的類型,爲了簡單起見,我們假設你正在流式傳輸String s,並且您想通過返回結果Set<String>的大小來檢查流中唯一String的數量。

類型的Collector的必須是Collector<String, ?, Integer>,這樣你就不會解決這個聲明(您想通過Set<String>確定的唯一String S中數的事實得到的是不相關的,因此第二參數可以是?)。

現在,您自然想要利用Collectors.toSet()。但是如何? A Collector有4個功能,一個供應商,一個累加器,一個組合器和一個終結器。從這4個,看起來你可以使用由Collectors.toSet()返回的Collector的前3個。現在這裏是擦:Collectors.toSet()返回類型實際上是Collector<T, ?, Set<T>>,與第二個類型參數,?,這表示積累類型,成爲問題。用非泛型術語來解釋這一點:你無法知道Collector如何在內部累積元素。你只知道完成函數將返回一個Set。但是,這並不一定意味着這些項目將在Set中累積。對於您所知道的,Collector可能會累積List中的項目,並且只有在完成階段纔會從List的內容創建Set。另一方面,您自定義的Collector(用於計算Set的大小)的精加工功能需要Set作爲輸入值,但由Collectors.toSet()返回的Collector無法保證它將元素累積到Set中。

不幸的是,這意味着,如果你想創建一個自定義Collector,其累積流元素爲Set,並在整理階段返回此Set的大小(或者是你想要與Set做任何其他)由Collectors.toSet()返回的收集器實際上是無用的,因爲supplier,accumulator和參數Collector.of(Supplier, BiConsumer, BinaryOperator, Function, Collector.Characteristics)的所有三個取決於不知道Collectors.toSet()的累積類型。

因此,最可行的解決方案似乎創建了一個輔助方法,首先使用Collectors.toSet()將流元素收集到Set中,然後手動執行完成轉換。讀Holger的答案,這似乎是一種方法,它已經存在。