在 Java8 中修改流中的对象,同时进行迭代
2022-08-31 10:52:36
在 Java8 流中,是否允许我修改/更新其中的对象?例如。:List<User> users
users.stream().forEach(u -> u.setProperty("value"))
在 Java8 流中,是否允许我修改/更新其中的对象?例如。:List<User> users
users.stream().forEach(u -> u.setProperty("value"))
是的,您可以修改流中对象的状态,但大多数情况下应避免修改流源的状态。从流包文档的非干扰部分,我们可以读到:
对于大多数数据源,防止干扰意味着确保在执行流管道期间根本不修改数据源。值得注意的例外是源是并发集合的流,这些集合专门设计用于处理并发修改。并发流源是那些报告特征的源。
Spliterator
CONCURRENT
所以这没关系
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
恕我直言,功能方式是:
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]
}
}
在此解决方案中,原始列表不会被修改,但应将预期结果包含在新列表中,该列表可在与旧列表相同的变量下访问