在 Java8 中修改流中的对象,同时进行迭代

2022-08-31 10:52:36

在 Java8 流中,是否允许我修改/更新其中的对象?例如。:List<User> users

users.stream().forEach(u -> u.setProperty("value"))

答案 1

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

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

所以这没关系

  List<User> users = getUsers();
  users.stream().forEach(u -> u.setProperty(value));
//                       ^    ^^^^^^^^^^^^^
//                        \__/

但在大多数情况下,这不是

  users.stream().forEach(u -> users.remove(u));
//^^^^^                       ^^^^^^^^^^^^
//     \_____________________/

并可能引发甚至其他意外异常,如 NPE:ConcurrentModificationException

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

list.stream()
    .filter(i -> i > 5)
    .forEach(i -> list.remove(i));  //throws NullPointerException

答案 2

恕我直言,功能方式是:

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]
    }
}

在此解决方案中,原始列表不会被修改,但应将预期结果包含在新列表中,该列表可在与旧列表相同的变量下访问


推荐