Java 8 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()来处理剩余的项目?

谢谢!

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

结果是一个只有两个Boolean条目的映射:对于true键,您有一个包含与谓词匹配的流元素的List,而对于false键,您有一个包含不匹配元素的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将始终有一个true的结果,并在Mapfalse,即如果没有元素落入该组,则为空列表,而不是null

这种特殊性已作为 API 说明添加到 jdk9 文档中(同样,用户@Holger观察到了这一点):

如果分区没有元素,则其在结果 Map 中的值将为空列表。

流接口中没有访问排除项的操作。但是,您可以实现更复杂的谓词:

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

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

最新更新