2017-05-04 135 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. */) 

但是你必须小心,以保持断言非干扰和无状态的。