迭代时在Java8中修改流内的对象

Tej*_*ale 68 java java-8 java-stream

在Java8流中,我可以修改/更新其中的对象吗?例如.List<User> users:

users.stream().forEach(u -> u.setProperty("value"))
Run Code Online (Sandbox Code Playgroud)

Psh*_*emo 80

是的,您可以修改流中的对象状态,但应避免修改流的状态.从流包文档的非干扰部分我们可以读到:

对于大多数数据源,防止干扰意味着确保在流管道的执行期间根本不修改数据源.值得注意的例外是其源是并发集合的流,这些集合专门用于处理并发修改.并发流源是那些Spliterator报告CONCURRENT特征的源.

所以这没关系

List<User> users = getUsers();
users.stream().forEach(u -> u.setProperty(value));
Run Code Online (Sandbox Code Playgroud)

users.stream().forEach(u -> users.remove(u));
Run Code Online (Sandbox Code Playgroud)

不是,可能会抛出ConcurrentModificationException像NPE这样的例外:

List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());

list.stream()
    .filter(i -> i > 5)
    .forEach(i -> list.remove(i));  //throws NullPointerException
Run Code Online (Sandbox Code Playgroud)

  • 如果要修改用户有什么解决办法? (4认同)
  • @Augustas这一切都取决于你想如何修改这个列表.但通常你应该避免`Iterator`在迭代时阻止修改列表(删除/添加新元素),并且两个流和for-each循环都在使用它.您可以尝试使用简单的循环,例如`for(int i = 0; ..; ..)`,它没有这个问题(但是当其他线程修改你的列表时不会阻止你).你也可以使用像`list.removeAll(Collection)`,`list.removeIf(Predicate)`这样的方法.此外,`java.util.Collections`类几乎没有像`addAll(CollectionOfNewElements,list)`那样有用的方法. (2认同)
  • @Blauhirn解决了什么?我们不允许在使用流时修改流的源,但允许修改其元素的状态.如果我们使用map,foreach或其他流方法并不重要. (2认同)

And*_*eim 5

恕我直言,功能方式是:

import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class PredicateTestRun {

    public static void main(String[] args) {

        List<String> lines = Arrays.asList("a", "b", "c");
        System.out.println(lines); // [a, b, c]
        Predicate<? super String> predicate = value -> "b".equals(value);
        lines = lines.stream().filter(predicate.negate()).collect(toList());

        System.out.println(lines); // [a, c]
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个解决方案中,原始列表没有被修改,但应该在一个新列表中包含您的预期结果,该列表可在与旧列表相同的变量下访问