【问题标题】:Java 8 Stream: Filter, process results, then process the exclusionsJava 8 Stream:过滤、处理结果,然后处理排除项
【发布时间】:2017-05-04 16:43:38
【问题描述】:

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

谢谢!

【问题讨论】:

标签: java java-8 java-stream


【解决方案1】:

看看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 将始终在Map 中获得truefalse 的结果,即如果没有元素落入该组,则为空列表,而不是null

此特殊性已作为 API 说明添加到 jdk9 docs(同样,用户 @Holger 注意到了这一点):

如果一个分区没有元素,它在结果 Map 中的值将是一个空 List。

【讨论】:

【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 2015-08-18
    • 2017-09-09
    • 1970-01-01
    相关资源
    最近更新 更多