Java 8 Stream:过滤,处理结果,然后处理排除

时间:2017-05-04 16:43:39

标签: java java-8 java-stream

在Java 8的Streams中,我知道如何基于谓词过滤集合,并处理谓词为真的项目。我想知道的是,如果谓词将集合分成两组,是否可以通过API根据谓词进行过滤,处理过滤后的结果,然后立即链接调用以处理所有排除的元素过滤器?

例如,请考虑以下列表:

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(),然后处理其余项目?

谢谢!

2 个答案:

答案 0 :(得分:11)

查看Collectors.partitioningBy,它接收谓词作为参数。您必须使用Stream.collect才能使用它。

结果是只有两个Boolean条目的映射:对于true键,您有一个List,其中包含与谓词匹配的流的元素,而对于{ {1}}密钥,您有false包含不匹配的元素。

请注意,List有一个重载版本,它接受第二个参数,如果您希望将每个分区收集到不同于列表的内容,则可以使用下游收集器。

在您的示例中,您可以这样使用它:

Collectors.partitioningBy

我还要强调一个重要的观察结果,取自用户@Holger在链接问题中添加的评论:

  

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] 将始终在Collectors.partitioningBy中显示truefalse的结果,即如果没有元素属于该组,则为空列表,而不是{{1 }}

此特殊性已作为API Note添加到jdk9 docs(同样,用户@Holger也观察到了这一点):

  

如果分区没有元素,则结果Map中的值将为空List。

答案 1 :(得分:1)

Stream界面中没有操作来访问排除的项目。但是,您可以实现更复杂的谓词:

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

但是你必须小心保持谓词不干扰和无状态。