Java 8 Streams 可以对集合中的项目进行操作,然后将其删除吗?

像几乎所有人一样,我仍然在学习新的Java 8 Streams API的复杂性(并且喜欢它们)。我有一个关于流使用的问题。我将提供一个简化的示例。

Java Streams 允许我们获取 一个 ,并使用它上面的方法来接收其所有元素的流。在其中,有许多有用的方法,例如 ,、 和 ,它们允许我们对内容使用 lambda 操作。Collectionstream()filter()map()forEach()

我有一些代码看起来像这样(简化):

set.stream().filter(item -> item.qualify())
    .map(item -> (Qualifier)item).forEach(item -> item.operate());
set.removeIf(item -> item.qualify());

这个想法是获取集合中所有项目的映射,这些项目与某个限定符匹配,然后通过它们进行操作。手术后,它们没有进一步的用途,应从原始集合中删除。代码运行良好,但我无法摆脱这样一种感觉,即有一个操作可以在一行中为我完成此操作。Stream

如果它在Javadocs中,我可能会忽略它。

有没有人更熟悉API看到这样的东西?


答案 1

你可以这样做:

set.removeIf(item -> {
    if (!item.qualify())
        return false;
    item.operate();
    return true;
});

如果总是返回,您可以非常简洁地完成。item.operate()true

set.removeIf(item -> item.qualify() && item.operate());

但是,我不喜欢这些方法,因为目前还不清楚发生了什么。就个人而言,我会继续为此使用循环和一个。forIterator

for (Iterator<Item> i = set.iterator(); i.hasNext();) {
    Item item = i.next();
    if (item.qualify()) {
        item.operate();
        i.remove();
    }
}

答案 2

在一行不,但也许你可以利用收集器:partitioningBy

Map<Boolean, Set<Item>> map = 
    set.stream()
       .collect(partitioningBy(Item::qualify, toSet()));

map.get(true).forEach(i -> ((Qualifier)i).operate());
set = map.get(false);

它可能更有效,因为它避免了迭代集两次,一次用于过滤流,另一次用于删除相应的元素。

否则,我认为您的方法相对较好。