Lambda 表达式遍历集合时用remove方法删除list集合中满足条件的元素问题
一:循环遍历list集合的四种方式
简单for循环
iterator循环
增加for循环
Lanbda表达式
二:四种遍历方式的用法示例
//简单for循环
List<SalaryAdjustmentFile> fileList = new ArrayList<>();
fileList.add(new SalaryAdjustmentFile());
//此处省略加入list元素
for(int i = 0; n < fileList.size(); i++){
.....//此处省略具体实现方法
}
//iterator循环
Iterator<SalaryAdjustmentFile> iter = fileList.iterator();
while(iter.hasNext()){
.....//此处省略具体实现方法
}
// 增强for循环
for(SalaryAdjustmentFile salaryAdjustmentFile : fileList){
.....//此处省略具体实现方法
}
//Lanbda表达式
fileList.stream().forEach(salaryAdjustmentFile -> {
.....//此处省略具体实现方法
});
三:删除集合元素
因为自己代码中是使用Lanbda表达式实现的list集合遍历,所以此处只展示这种方式遍历集合删除元素的功能
fileList.stream().forEach(salaryAdjustmentFile -> {
String staffId = salaryAdjustmentFile.getStaffId();
String modelFieldName = salaryAdjustmentFile.getModelFieldName();
String tenantId = BaseContextHandler.getTenantId();
String salaryPlanId = salaryAdjustmentFile.getSalaryPlanId();
SalaryAdjustmentFile last = salaryAdjustmentFileMapper.selectLastTimeFile(staffId,modelFieldName,salaryPlanId,tenantId);
Map map = salaryFileMapper.selectItemValueByStaffId(staffId,modelFieldName,salaryPlanId,tenantId);
if(StringUtils.isEmpty(last) && !map.isEmpty()){
salaryAdjustmentFile.setValueBeforeAdjustment((BigDecimal) map.get("itemValue"));
}else {
salaryAdjustmentFile.setValueBeforeAdjustment(last.getValueAfterAdjustment());
}
salaryAdjustmentFile.creat(idWorker.nextStringId());
//如果满足下面条件则删除元素
if((salaryAdjustmentFile.getValueBeforeAdjustment().subtract(salaryAdjustmentFile.getValueAfterAdjustment()) == BigDecimal.ZERO)){
fileList.remove(salaryAdjustmentFile);
}
});
上面的代码在运行的时候,并不会如我们期望的一样删除list元素成功,而是控制台会报错java.lang.NullPointerException: null
报错原因分析:
经过百度搜索了解到,这是并发修改异常错误,是集合遍历原理导致的,具体原因是这样的:
不管是哪种方式的集合遍历方法,当我们在遍历某个集合的时候,Collection的实现并没有同步化,如果在多线程应用程序中出现同时访问,而且出现修改操作的时候都要求外部操作同步化;调用遍历操作获得的遍历对象在多线程修改集合的时候也自动失效,并抛出java.util.ConcurrentModificationException。这种实现机制是fail-fast,对外部 的修改并不能提供任何保证。遍历对象在被创建的时候,同时创建了一张单链的索引表,指针指向原始数据对象,只能顺序读取,不能逆向操作,而set、list等集合是动态、可变的数据结构;当原始对象改变时,索引并为改变,因此,索引指针继续移动的时候,找不到要迭代的对象就会报错。
四:针对第三步中错误的解决方案
将删除对象放在一个临时的集合中,最后执行removeAll方法移除,如下:
List<SalaryAdjustmentFile> removeList = new ArrayList<>();
fileList.stream().forEach(salaryAdjustmentFile -> {
String staffId = salaryAdjustmentFile.getStaffId();
String modelFieldName = salaryAdjustmentFile.getModelFieldName();
String tenantId = BaseContextHandler.getTenantId();
String salaryPlanId = salaryAdjustmentFile.getSalaryPlanId();
SalaryAdjustmentFile last = salaryAdjustmentFileMapper.selectLastTimeFile(staffId,modelFieldName,salaryPlanId,tenantId);
Map map = salaryFileMapper.selectItemValueByStaffId(staffId,modelFieldName,salaryPlanId,tenantId);
if(StringUtils.isEmpty(last) && !map.isEmpty()){
salaryAdjustmentFile.setValueBeforeAdjustment((BigDecimal) map.get("itemValue"));
}else {
salaryAdjustmentFile.setValueBeforeAdjustment(last.getValueAfterAdjustment());
}
salaryAdjustmentFile.creat(idWorker.nextStringId());
//如果满足下面条件则删除元素
if((salaryAdjustmentFile.getValueBeforeAdjustment().subtract(salaryAdjustmentFile.getValueAfterAdjustment()) == BigDecimal.ZERO)){
removeList.add(salaryAdjustmentFile);
}
});
//删除掉集合中满足删除条件的数据
fileList.removeAll(removeList);
Lambda 表达式遍历集合时用remove方法删除list集合中满足条件的元素问题的更多相关文章
- java 数据类型:集合接口Collection之常用ArrayList;lambda表达式遍历;iterator遍历;forEachRemaining遍历;增强for遍历;removeIf批量操作集合元素(Predicate);
java.util.Collection接口 Java的集合主要由两个接口派生出来,一个是Collection一个是Map,本章只记录Collection常用集合 集合只能存储引用类型数据,不能存储基 ...
- Java Map集合 遍历 五种方式(包含 Lambda 表达式遍历)
示例代码如下: package com.miracle.luna.lambda; import java.util.HashMap; import java.util.Iterator; import ...
- Java List集合 遍历 四种方式(包含 Lambda 表达式遍历)
示例代码如下: package com.miracle.luna.lambda; import java.util.ArrayList; import java.util.List; /** * @A ...
- Java Array数组 遍历 四种方式(包含 Lambda 表达式遍历)
示例代码如下: package com.miracle.luna.lambda; import java.util.Arrays; /** * @Author Miracle Luna * @Date ...
- C#中分别对委托、匿名方法、Lambda表达式、Lambda表达式树以及反射执行同一方法的过程进行比较。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 【转载】C#中List集合使用LastOrDefault方法查找出最后一个符合条件的元素
在C#的List集合中,FirstOrDefault方法一般用来查找List集合中第一个符合条件的对象,如果未查到则返回相应默认值.其实如果要查找最后一个符合条件的List集合元素对象,可以使用Las ...
- 【转载】C#通过Remove方法移除DataTable中的某一列数据
在C#中的Datatable数据变量的操作过程中,有时候我们需要移除当前DataTable变量中的某一列的数据,此时我们就需要使用到DataTable变量内部的Columns属性变量的Remove方法 ...
- 在Python的列表中利用remove()方法删除元素的教程
在Python的列表中利用remove()方法删除元素的教程 这篇文章主要介绍了在Python的列表中利用remove()方法删除元素的教程,是Python入门中的基础知识,注意其和pop()方法的区 ...
- Lambda表达式遍历集合
1.Collection Java 8 为Iterable接口新增了一个forEach(Consumer action)默认方法,该方法所需参数的类型是一个函数式接口,而Iterable接口是Coll ...
随机推荐
- 怒肝俩月,新鲜出炉史上最有趣的Java小白手册,第一版,每个 Java 初学者都应该收藏
这么说吧,在我眼里,Java 就是最流行的编程语言,没有之一(PHP 往一边站).不仅岗位多,容易找到工作,关键是薪资水平也到位,不学 Java 亏得慌,对吧? 那可能零基础学编程的小伙伴就会头疼了, ...
- qt解决release后数据库连接不上的问题
问题 : 明明已经设置了 "./xxx" , 为什么release之后数据库还是连不上呢 解决 : 项目中建立一个plugins文件夹 将qt安装目录下的sqldrivers复制到 ...
- springboot整合oss
原文链接:https://blog.csdn.net/weixin_42370891/article/details/99102508 登录阿里云,进入到控制台 创建Bucket 导入如下依赖 < ...
- HashSet扩容机制在时间和空间上的浪费,远大于你的想象
一:背景 1. 讲故事 自从这个纯内存项目进了大客户之后,搞得我现在对内存和CPU特别敏感,跑一点数据内存几个G的上下,特别没有安全感,总想用windbg抓几个dump看看到底是哪一块导致的,是我的代 ...
- 一文梳理JS事件
JavaScript与HTML的交互是通过事件进行的.事件,就是文档或浏览器窗口发生的一些特定的交互瞬间. 事件流 事件捕获 事件冒泡 事件处理程序 事件委托 1. 事件流 如果单机页面上的某个按钮, ...
- C++核心编程
C++核心编程 本阶段主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓. 1 内存分区模型 C++程序在执行时,将内存大方向划分为4个区域 代码区:存放函数体的二进制代码,由操作系统 ...
- Kubernetes学习笔记(九):StatefulSet--部署有状态的多副本应用
StatefulSet如何提供稳定的网络标识和状态 ReplicaSet中的Pod都是无状态,可随意替代的.又因为ReplicaSet中的Pod是根据模板生成的多副本,无法对每个副本都指定单独的PVC ...
- maven依赖冲突以及解决方法
什么是依赖冲突 依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突 依赖冲突的原因 依赖冲突很经常是类包之间的间接依赖引起的.每个显式声明的类包都会依赖于一些其它的隐式类包, ...
- ps学习。
ps软件及教程,这些东西,你应该要花一辈子来消化.
- java 中的 自定义viewUtils框架
在前面学习的基础上,我们自己编写一个ViewUtils注解框架类,不清楚的原理看前面的源代码 package im.weiyuan.com.viewutils; import android.supp ...