2017-05-04 130 views
5

在Java 8的Streams中,我知道如何基於謂詞過濾集合,並處理謂詞爲true的項目。我想知道的是,如果謂詞將集合分爲兩組,那麼是否可以通過API基於謂詞進行過濾,處理過濾結果,然後立即鏈接調用以處理過濾器排除的所有元素?Java 8流:過濾,處理結果,然後處理排除

例如,請考慮以下列表:

List<Integer> intList = Arrays.asList(1,2,3,4); 

是否有可能做的事:

intList.stream() 
    .filter(lessThanThree -> lessThanThree < 3) 
    .forEach(/* process */) 
    .exclusions(/* process exclusions */); //<-- obviously sudocode 

或將我只是做了forEach過程經過濾項,然後調用stream()並在原始列表中filter()然後處理剩餘的項目?

謝謝!

+4

https://stackoverflow.com/q/43766534/2711488 – Holger

回答

8

看看Collectors.partitioningBy,它接收謂詞作爲參數。您必須使用Stream.collect才能使用它。

結果是僅具有兩個Boolean條目的圖:爲true鍵,有一個包含匹配謂詞,而對於false鍵之前,必須含有沒元素的List流的元素List不匹配。

請注意,Collectors.partitioningBy有一個接受第二個參數的重載版本,它是一個下游採集器,如果您希望將每個分區收集到不同於列表的某個分區,那麼您可以使用該參數。

在您的例子,你可以使用這種方式:

Map<Boolean, List<Integer>> partition = intList.stream() 
    .collect(Collectors.partitioningBy(i -> i < 3)); 

List<Integer> lessThan = partition.get(true); // [1, 2] 
List<Integer> notLessThan = partition.get(false); // [3, 4] 

我也想強調一個重要的觀察,從用戶@Holger在鏈接的問題添加了評論次數:

Collectors.partitioningBy對於Map中的truefalse將始終有結果,即如果沒有元素落入該組中,則爲空列表,而不是null

此特殊性已被添加到jdk9 docs作爲API注(再次,這是由用戶@Holger觀察到的):

如果一個分區沒有任何元素,其在結果地圖值將是一個空的列表。

+2

您可以從http://www.concretepage獲取樣本。COM /爪哇/ JDK-8/java的8 - 收集-partitioningby-示例 –

1

Stream接口沒有操作來訪問排除的項目。但是,您可以實現更復雜的斷言:

intList.stream() 
    .filter(i -> { 
     if (i < 3) return true; 
     else { 
      // Process excluded item i 
      return false; 
     } 
    }).forEach(/* Process included item. */) 

但是你必須小心,以保持斷言非干擾和無狀態的。