java 动态 Lambda (二)
相较于
https://blog.csdn.net/hanjun0612/article/details/121972663?spm=1001.2014.3001.5501
这次添加了更多的指令
一,反射类
package com.leadtrans.report.common; import org.springframework.aop.support.AopUtils; import org.springframework.context.ApplicationContext; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.*; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @author: Tyler * @createDate: 2021/12/9 */ public class ReflectionUtil { /** * 调用示例 * public ApiResponsetest() throws Exception { * Class[] argsType=new Class[]{Class.forName("java.lang.String")}; * Object[] args=new Object[]{"hello"}; * ReflectionUtil.invokeMethod(new ReportImpl(),"Test",argsType,args); * return new ApiResponse().Success("str"); * } * @param owner 类的实例 * @param methodName 方法名 * @param argsClass 参数类型 * @param args 参数 * @return * @throws Exception */ public static Object invokeMethod(Object owner,String methodName,Class[] argsClass,Object[] args) throws Exception{ Object objRtn=null; Class ownerClass = owner.getClass(); Method method = ownerClass.getMethod(methodName, argsClass); objRtn = method.invoke(owner, args); return objRtn; } public static Field getFiled(Object obj,String filedName){ Field field=null; try { field = obj.getClass().getDeclaredField(filedName); field.setAccessible(true); } catch (NoSuchFieldException e) { e.printStackTrace(); } finally { return field; } } public static Object getFiledValue(Object obj,String filedName){ Object objValue=null; try { Field field = getFiled(obj,filedName); objValue = field.get(obj); }catch (IllegalAccessException e) { e.printStackTrace(); } finally { return objValue; } } }
二,动态lambda
Filter
/** * Lambda 动态 Filter * * @param list 数据 * @param equalsMap contains 过滤器 * @param notEqualsMap !contains 过滤器 * @param* @return */ publicList getDataListFilter(List list, Map > equalsMap, Map > notEqualsMap,Map > containsMap, Map dateLessMap, Map > startWithMap, Map > notStartWithMap) { //相等 LambdaFilter equalsFilter = new EqualsFilter(); list = equalsFilter.filer(list, equalsMap); //不等 LambdaFilter notEqualsFilter = new NotEqualsFilter(); list = notEqualsFilter.filer(list, notEqualsMap); //包含 LambdaFilter containsFilter=new ContainsFilter(); list = containsFilter.filer(list,containsMap); //时间小于 LambdaBaseFilter dateLessFilter = new DateLessFilter(); list = dateLessFilter.filer(list, dateLessMap); //前缀相同 LambdaFilter startWithFilter = new StartWithFilter(); list = startWithFilter.filer(list, startWithMap); //前缀不同 LambdaFilter notStartWithFilter = new NotStartWithFilter(); list = notStartWithFilter.filer(list, notStartWithMap); List rList = list; return rList; }
过滤类:
1,base接口
public interface LambdaBaseFilter{ List filer(List st, Map map); }
2,接口
public interface LambdaFilterextends LambdaBaseFilter > { List filer(List st, Map > map); }
3,EqualsFilter
package com.leadtrans.report.common.lambdaReport.filter; import com.leadtrans.report.common.ReflectionUtil; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author: Tyler * @createDate: 2022/1/13 */ /** * 需要过滤的相等字段 * "equalsMap": {"mode": ["FCL","BCN"],"importOrExport": ["Export","Other"]}, * 筛选 mode等于FCL或BCN,并且importOrExport等于Export或Other * @param*/ public class EqualsFilter implements LambdaFilter { @Override public List filer(List st, Map > map) { if (map != null) { for (Map.Entry > item : map.entrySet()) { st = st.stream() .filter(x -> item.getValue().contains( ReflectionUtil.getFiledValue(x, item.getKey()) == null ? "null" : ReflectionUtil.getFiledValue(x, item.getKey())) ) .collect(Collectors.toList()); } } return st; } }
4,NotEqualsFilter
package com.leadtrans.report.common.lambdaReport.filter; import com.leadtrans.report.common.ReflectionUtil; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author: Tyler * @createDate: 2022/1/13 */ /** * 需要过滤的不等字段 * "notEqualsMap": {"invoiceStatus": ["WHL","OTHER"]}, * 筛选invoiceStatus不等于WHL或OTHER * @param*/ public class NotEqualsFilter implements LambdaFilter { @Override public List filer(List st, Map > notEqualsMap) { if (notEqualsMap != null) { for (Map.Entry > item : notEqualsMap.entrySet()) { st = st.stream() .filter(x -> !item.getValue().contains( ReflectionUtil.getFiledValue(x, item.getKey()) == null ? "null" : ReflectionUtil.getFiledValue(x, item.getKey())) ) .collect(Collectors.toList()); } } return st; } }
5,ContainsFilter
package com.leadtrans.report.common.lambdaReport.filter; import com.leadtrans.report.common.ReflectionUtil; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author: Tyler * @createDate: 2022/1/25 */ /** * 包含过滤器 * "containsMap": {"OSOCCreditor": ["SHALEASHA"]}, * 筛选 OSOCCreditor 包含SHALEASHA * @param*/ public class ContainsFilter implements LambdaFilter { @Override public List filer(List st, Map > map) { if (map != null) { for (Map.Entry > item : map.entrySet()) { for (Object it : item.getValue()) { st = st.stream() .filter(x -> (ReflectionUtil.getFiledValue(x, item.getKey()) == null ? "" : ReflectionUtil.getFiledValue(x, item.getKey()).toString() ) .contains(it.toString()) ) .collect(Collectors.toList()); } } } return st; } }
6,DateLessFilter
package com.leadtrans.report.common.lambdaReport.filter; import com.leadtrans.report.common.DateUtils; import com.leadtrans.report.common.ReflectionUtil; import org.apache.commons.lang3.StringUtils; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author: Tyler * @createDate: 2022/1/13 */ /** * 日期过滤 * "dateLessMap":{"jw_ATD": 5} * 筛选jw_ATD增加5天后,小于当天的数据 * @param*/ public class DateLessFilter implements LambdaBaseFilter { @Override public List filer(List st, Map map) { if (map != null) { for (Map.Entry item : map.entrySet()) { st = st.stream() .filter(x -> { Object colVal = ReflectionUtil.getFiledValue(x, item.getKey()); if (colVal != null && StringUtils.isNotBlank(colVal.toString())) { colVal = DateUtils.add(DateUtils.parse2(colVal.toString()), Calendar.DATE, item.getValue()); return new Date().after((Date) colVal); } return false; }) .collect(Collectors.toList()); } } return st; } }
7,StartWithFilter
package com.leadtrans.report.common.lambdaReport.filter; import com.leadtrans.report.common.ReflectionUtil; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author: Tyler * @createDate: 2022/1/13 */ /** * 前缀包含 * "startWithMap":{"country":["CN"]} * 筛选 前缀为CN开头的 * @param*/ public class StartWithFilter implements LambdaFilter { @Override public List filer(List st, Map > map) { if (map != null) { List stResult=new ArrayList<>(); for (Map.Entry > item : map.entrySet()) { for (Object it : item.getValue()) { st = st.stream() .filter(x -> (ReflectionUtil.getFiledValue(x, item.getKey()) == null ? "" : ReflectionUtil.getFiledValue(x, item.getKey()).toString() ) .startsWith(it.toString()) ) .collect(Collectors.toList()); stResult.addAll(st); } } return stResult; } else { return st; } } }
8,NotStartWithFilter
package com.leadtrans.report.common.lambdaReport.filter; import com.leadtrans.report.common.ReflectionUtil; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author: Tyler * @createDate: 2022/1/13 */ /** * 前缀过滤 * "notStartWithMap": {"houseBill": ["W"]}, * 筛选houseBill不以W开头 * @param*/ public class NotStartWithFilter implements LambdaFilter { @Override public List filer(List st, Map > map) { if (map != null) { for (Map.Entry > item : map.entrySet()) { for (Object it : item.getValue()) { st = st.stream() .filter(x -> !(ReflectionUtil.getFiledValue(x, item.getKey()) == null ? "" : ReflectionUtil.getFiledValue(x, item.getKey()).toString() ) .startsWith(it.toString()) ) .collect(Collectors.toList()); } } } return st; } }
Group
/** * Lambda 动态 Group * * @param list 数据 * @param fieldGroups 聚合字段 * @param* @return */ publicMap > getDataListGroup(List list, List fieldGroups) { Map > map = list.stream().collect(Collectors.groupingBy(x -> { String groupItem = ""; for (String y : fieldGroups) { groupItem += ReflectionUtil.getFiledValue(x, y) + "_"; } return groupItem; })); return map; }
Calculate 计算命令
CalCulate 计算
/** * 输出数据 * * @param dataList 数据源 * @param fieldNames 属性名 * @param calculateNames 需要计算的列 * @return */ publicList > getDataList(Map
> dataList, List fieldNames, List calculateNames) { List > data = new ArrayList<>(); for (Map.Entry
> entry : dataList.entrySet()) { List
接口:
public interface LambdaCalculate{ default Object calculate(List list, String colName){ return calculate(null,list,colName); } Object calculate(Object key,List list,String colName); }
1,NotCalculate
package com.leadtrans.report.common.lambdaReport.calculateTag; import com.leadtrans.report.common.DateUtils; import com.leadtrans.report.common.ReflectionUtil; import org.apache.commons.lang3.StringUtils; import java.util.Calendar; import java.util.List; /** * @author: Tyler * @createDate: 2022/1/14 */ /** * 无需计算 * 假设使用addDate(xxx,5) 则表示xxx增加5天 * 其他属性则直接展示 * @param*/ public class NotCalculate implements LambdaCalculate { @Override public Object calculate(Object key, List list, String colName) { Object colVal=null; //addDate if (colName.toLowerCase().replace(" ", "").startsWith("addDate(".toLowerCase())) { String addDateName = colName.substring("addDate(".length(), colName.indexOf(")")); String[] args = addDateName.split(","); colVal = ReflectionUtil.getFiledValue(list.get(0), args[1]); if (colVal != null && StringUtils.isNotBlank(colVal.toString())) { colVal = DateUtils.toDateString(DateUtils.add(DateUtils.parse2(colVal.toString()), Calendar.DATE, Integer.parseInt(args[0])), "yyyy-MM-dd"); } } else { //判断属性是否存在 Object col = ReflectionUtil.getFiled(list.get(0), colName); if (col == null) { col=key; } else { //属性存在,则取值 colVal = ReflectionUtil.getFiledValue(list.get(0), colName); } } return colVal; } }
2,NormalCalculate
package com.leadtrans.report.common.lambdaReport.calculateTag; import com.leadtrans.report.common.ReflectionUtil; import java.math.BigDecimal; import java.util.List; /** * @author: Tyler * @createDate: 2022/1/14 */ /** * xxx 计算器 * 按照某一列,计算数值 * @param*/ public class NormalCalculate implements LambdaCalculate { @Override public Object calculate(Object key, List list, String colName) { Object colVal = list.stream() .map(x -> new BigDecimal(ReflectionUtil.getFiledValue(x, colName) == null ? "0" : ReflectionUtil.getFiledValue(x, colName).toString().replace(",", ""))) .reduce(BigDecimal.ZERO, BigDecimal::add); return colVal; } }
3,CountCalculate
package com.leadtrans.report.common.lambdaReport.calculateTag; import com.leadtrans.report.common.ReflectionUtil; import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @author: Tyler * @createDate: 2022/1/14 */ /** * count(xxx) 计算器 * 按照某一列,计算总数 * @param*/ public class CountCalculate implements LambdaCalculate { @Override public Object calculate(Object key, List list, String colName) { Object colVal=null; String countName = colName.substring("count(".length(), colName.indexOf(")")); String[] args = countName.split(","); //如果args>1,说明有条件 if (args.length > 1) { //获取多个条件 String[] argsArr = args[0].split("&"); Supplier > st = () -> list.stream(); for (String argsSimple : argsArr) { Supplier > stFilter = st; //获取单个条件,拼接 String[] argsKV; if (argsSimple.indexOf("!:") > 0) { //不等 argsKV = argsSimple.split("!:"); st = () -> stFilter.get() .filter(x -> !argsKV[1].contains(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString())); } else { //相等 argsKV = argsSimple.split(":"); st = () -> stFilter.get() .filter(x -> argsKV[1].contains(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString())); } } colVal = st.get().collect(Collectors.toList()).size(); } else { colVal = list.size(); } return colVal; } }
4,CountDistinctCalculate
package com.leadtrans.report.common.lambdaReport.calculateTag; import com.leadtrans.report.common.ReflectionUtil; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @author: Tyler * @createDate: 2022/1/14 */ /** * countDistinct(xxx) 计算器 * 按照某一列,计算去重后总数 * @param*/ public class CountDistinctCalculate implements LambdaCalculate { @Override public Object calculate(Object key, List list, String colName) { Object colVal=null; String countName = colName.substring("countDistinct(".length(), colName.indexOf(")")); String[] args = countName.split(","); //如果args>1,说明有条件 if (args.length > 1) { //获取多个and条件 String[] argsArr = args[0].split("&"); Supplier > st = () -> (Stream ) list.stream(); for (String argsSimple : argsArr) { Supplier > stFilter = st; //获取单个条件,拼接 String[] argsKV; //不等 if (argsSimple.indexOf("!:") > 0) { argsKV = argsSimple.split("!:"); st = () -> stFilter.get() .filter(x -> !argsKV[1].contains(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString())) ; } else { //相等 argsKV = argsSimple.split(":"); st = () -> stFilter.get() .filter(x -> argsKV[1].contains(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString())) ; } } colVal = st.get() .map(x -> ReflectionUtil.getFiledValue(x, args[1])) .distinct() .collect(Collectors.toList()).size(); } else { colVal = list.stream() .map(x -> ReflectionUtil.getFiledValue(x, args[0])) .distinct() .collect(Collectors.toList()).size(); } return colVal; } }
5,SumCalculate
package com.leadtrans.report.common.lambdaReport.calculateTag; import com.leadtrans.report.common.ReflectionUtil; import java.math.BigDecimal; import java.util.List; import java.util.function.Supplier; import java.util.stream.Stream; /** * @author: Tyler * @createDate: 2022/1/14 */ /** * sum(xxx) 计算器 * 按照某一列,计算总和 * @param*/ public class SumCalculate implements LambdaCalculate { @Override public Object calculate(Object key, List list, String colName) { Object colVal=null; String sumName = colName.substring("sum(".length(), colName.indexOf(")")); String[] args = sumName.split(","); //如果args>1,说明有条件 if (args.length > 1) { //获取多个条件 String[] argsArr = args[0].split("&"); Supplier > st = () -> list.stream(); for (String argsSimple : argsArr) { Supplier > stFilter = st; //获取单个条件,拼接 String[] argsKV; //不等 if (argsSimple.indexOf("!:") > 0) { argsKV = argsSimple.split("!:"); st = () -> stFilter.get() .filter(x -> !argsKV[1].contains(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString())); } else { //相等 argsKV = argsSimple.split(":"); st = () -> stFilter.get() .filter(x -> argsKV[1].contains(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString())); } } colVal = st.get() .map(x -> new BigDecimal(ReflectionUtil.getFiledValue(x, args[1]) == null ? "0" : ReflectionUtil.getFiledValue(x, args[1]).toString().replace(",", ""))) .reduce(BigDecimal.ZERO, BigDecimal::add); } else { colVal = list.stream() .map(x -> new BigDecimal(ReflectionUtil.getFiledValue(x, args[0]) == null ? "0" : ReflectionUtil.getFiledValue(x, args[0]).toString().replace(",", ""))) .reduce(BigDecimal.ZERO, BigDecimal::add); } return colVal; } }
总计列
/** * 添加合计列 * * @param fieldNames 字段 * @param data 数据 * @param calculateHeadsNames 计算列 * @return */ public List
三,测试
@Test public void testLambda() throws NoSuchFieldException, IllegalAccessException { Listlist=new ArrayList<>(); list.add(new MyTest(0,"n0","hobby0",1)); list.add(new MyTest(1,"n1","hobby1",1)); list.add(new MyTest(1,"n2","hobby2",1)); list.add(new MyTest(2,"n3","hobby3",1)); list.add(new MyTest(2,"n4","hobby4",1)); list.add(new MyTest(3,"n5","hobby5",1)); list.add(new MyTest(3,"n6","hobby6",1)); list.add(new MyTest(3,"n7","hobby7",1)); list.add(new MyTest(3,"n8","hobby7",1)); String json = FileUtil.readFile(System.getProperty("user.dir") + "/reportArgs"+"/myTest.json"); ReportArgsReq reportArgsReq= JSON.parseObject(json,ReportArgsReq.class); List rList = report.getDataListFilter(list, reportArgsReq.getEqualsMap(),reportArgsReq.getNotEqualsMap()); Map > rMap=report.getDataListGroup(rList,reportArgsReq.getFieldGroups()); System.out.println(rMap.size()); // List rList=list.stream().filter(x->x.) }
MyTest.java
package com.leadtrans.report.model.DB; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.util.Date; /** * @author: Tyler * @createDate: 2021/12/7 */ @TableName(value = "myTest") public class MyTest { @TableId private Integer id; private String name; private String hobby; private Integer amount; public MyTest(){} public MyTest(Integer id,String name,String hobby,Integer amount){ this.id=id; this.name=name; this.hobby=hobby; this.amount=amount; } //get;set; }
myTest.json
{ "equalsMap": {}, "notEqualsMap": {}, "fieldGroups": ["id"], "headsExcel": ["id","name","hobby","amount sum"], "fieldNames": ["id","name","hobby","sum(amount)"], "calculateFieldNames": ["sum(amount)"] }
四,进阶
其实还有一些其他的用法。
样例:
{ "equalsMap": {"INCO": ["FOB","EXWORK"],"Test": ["a","b"]}, "notEqualsMap": {"Test1": ["hello"],"Test2": ["t1","t2"]}, "fieldGroups": ["pol","pod","jobName"], "headsExcel": ["jobName","pol","pod","INCO","TEU","AIR Bill","LCL Bill","jobProfit"], "fieldNames": ["jobName","pol","pod","INCO","sum(type:SEA&mode:FCL,TEU)","count(type:AIR,shipmentID)","count(mode:LCL,shipmentID)","jobProfit"], "calculateFieldNames": ["sum(type:SEA&mode:FCL,TEU)","count(type:AIR,shipmentID)","count(mode:LCL,shipmentID)","jobProfit"] }
解释:
字段 注释 equalsMap 需要过滤的相等字段。 notEqualsMap 需要过滤的不等字段。 startWithMap 前缀包含,以xxx开头 notStartWithMap 前缀过滤,不以xxx开头 dateLessMap 日期比较, "dateLessMap":{"jw_ATD": 5} 筛选出jw_ATD增加5天后,小于当天的数据 fieldTag 无需设置,备用字段。 目前用途: 1 动态字段拼接sql 2 两个报表根据某个字段进行 交集,差集,并集 fieldGroups 分组字段。 headsExcel 写入excel的表头 fieldNames 使用到的字段,对应到表头。 calculateFieldNames 需要计算的字段,int,decimal..... ( 匹配相等的合计 sum(type:SEA&mode:FCL,TEU) : 计算type为sea,并且mode为FCL 的TEU 总和 匹配相等的数量 count(type:AIR,shipmentID):计算type为Air,的shipment数量 匹配不等的合计 sum(type!:SEA&mode!:FCL,TEU) : 计算type不为sea,并且mode不为FCL 的TEU 总和 匹配不等的数量 count(type!:AIR,shipmentID):计算type不为Air,的shipment数量 合计 sum(jobProfit):计算jobProfit的总合 去重的数量 countDistinct(type:AIP,shipmentID):去重后计算count )