一、起因
今天发现线上系统出现了一个bug,
我有一个“定时任务”每天凌晨触发,任务内容:
① 定时调用的系统暴漏的接口,来定时获取List<Object>数据。
② 然后我会筛选出该List中符合条件的Object,对筛选出来的Object的某个属性进行修改。
③ 最后将该List<Object>全部保存到数据库(包括修改和未修改的都保存下来)。
二、问题
发现定时执行的任务,每天触发成功了,也没有报错。但是定时任务中对List修改的值并没有全部生效。大多数都未修改成功,而偶尔修改的成功的还是获取的List<Object>中的部分数据。
三、解决
上网查阅一番,初步判断是因为使用了java8的Stream.foreach()来修改“流的源数据”导致的。官方文档中有说明:Stream (Java Platform SE 8 )
其中,对参数有特别说明“a non-interfering action to perform on the elements”,意思是说,对元素执行的非干扰动作,即foreach中执行的方法不要修改“stream流的元数据”。
而官网有对no-interfering更进一步说明java.util.stream (Java Platform SE 8 ):
大概意思:
永远不应该修改流的数据源。在流管道执行期间修改流的数据源可能会导致异常、不正确的答案或不一致的行为。
如果要改,则看截图中的代码示例,可以在终端操作开始之前修改源,这些修改将反映在所覆盖的元素中。
所以,如果要修改List数据
- 方式一:
要么就如同官网说的,在List进入Stream处理之前改。- 方式二:
要么使用List<Object> newList= list.stream().map(e -> e.setXXX("123")).collect(Collection.toList);
这种map的方式最后使用collect()接一下,保存到一个新list中(如果不使用collect接收并且保存到新list中,那么有些情况下会导致对List的修改无效)。- 方式三(推荐):
要么直接使用list.foreach(e -> e.setXXX("123")),中间不需要Stream!!中间不需要Stream!!中间不需要Stream!!
参考链接:
Stream (Java Platform SE 8 )
java.util.stream (Java Platform SE 8 )
list.stream().foreach()和list.foreach()的对比_初Q,的博客-CSDN博客_list.stream().foreach