java 动态 Lambda

Posted 正怒月神

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 动态 Lambda相关的知识,希望对你有一定的参考价值。

相较于java 动态 lambda_正怒月神的博客-CSDN博客最近有需求,需要根据配置文件,动态的 过滤+聚合 数据想想就写了动态的lambda,方便使用。目前只有 filter和group。并且没有测试过性能。如果大家使用的话,先将就一下,或者自己改改。一,主要方法类通过反射,来组装lambda。主要使用方法:getFiledValuegetDataListFiltergetDataListGrouppackage com.leadtrans.report.common;import org.spr.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 ApiResponse<String> test() 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 <T>
     * @return
     */
    public <T> List<T> getDataListFilter(List<T> list, Map<String, List<Object>> equalsMap, Map<String, List<Object>> notEqualsMap, Map<String, Integer> dateLessMap) 
        Supplier<Stream<T>> st = () -> list.stream();
        if (equalsMap != null) 
            for (Map.Entry<String, List<Object>> item : equalsMap.entrySet()) 
                Supplier<Stream<T>> stFilter = st;
                st = () -> stFilter.get()
                        .filter(x -> item.getValue().contains(
                                ReflectionUtil.getFiledValue(x, item.getKey()) == null
                                        ? "null"
                                        : ReflectionUtil.getFiledValue(x, item.getKey()))
                        );
            
        
        if (notEqualsMap != null) 
            for (Map.Entry<String, List<Object>> item : notEqualsMap.entrySet()) 
                Supplier<Stream<T>> stFilter = st;
                st = () -> stFilter.get()
                        .filter(x -> !item.getValue().contains(
                                ReflectionUtil.getFiledValue(x, item.getKey()) == null
                                        ? "null"
                                        : ReflectionUtil.getFiledValue(x, item.getKey()))
                        );
            
        
        if (dateLessMap != null) 
            for (Map.Entry<String, Integer> item : dateLessMap.entrySet()) 
                Supplier<Stream<T>> stFilter = st;
                st = () -> stFilter.get()
                        .filter(x -> 
                            Object colVal = ReflectionUtil.getFiledValue(x, item.getKey());
                            if (colVal != null && StringUtils.isNotBlank(colVal.toString())) 
                                colVal = DateUtil.add(DateUtil.parse2(colVal.toString()), Calendar.DATE, item.getValue());
                                return new Date().after((Date)colVal);
                            
                            return false;
                        );
            
        

        List<T> rList = st.get().collect(Collectors.toList());
        return rList;
    

Group

/**
     * Lambda 动态 Group
     *
     * @param list        数据
     * @param fieldGroups 聚合字段
     * @param <T>
     * @return
     */
    public <T> Map<String, List<T>> getDataListGroup(List<T> list, List<String> fieldGroups) 
        Map<String, List<T>> map = list.stream().collect(Collectors.groupingBy(x -> 
            String groupItem = "";
            for (String y : fieldGroups) 
                groupItem += ReflectionUtil.getFiledValue(x, y) + "_";
            
            return groupItem;
        ));
        return map;
    

获取数据

/**
     * 输出数据
     *
     * @param dataList       数据源
     * @param fieldNames     属性名
     * @param calculateNames 需要计算的列
     * @return
     */
    public <T> List<List<Object>> getDataList(Map<String, List<T>> dataList, List<String> fieldNames, List<String> calculateNames) 
        List<List<Object>> data = new ArrayList<>();
        for (Map.Entry<String, List<T>> entry : dataList.entrySet()) 
            List<Object> obj = new ArrayList<>();
            for (String colName : fieldNames) 
                //普通字段
                if (!calculateNames.contains(colName)) 
                    //addDate
                    if (colName.toLowerCase().replace(" ", "").startsWith("addDate(".toLowerCase())) 
                        String addDateName = colName.substring("addDate(".length(), colName.indexOf(")"));
                        String[] args = addDateName.split(",");
                        Object colVal = ReflectionUtil.getFiledValue(entry.getValue().get(0), args[1]);
                        if (colVal != null && StringUtils.isNotBlank(colVal.toString())) 
                            colVal = DateUtil.toDateString(DateUtil.add(DateUtil.parse2(colVal.toString()), Calendar.DATE, Integer.parseInt(args[0])), "yyyy-MM-dd");
                        
                        obj.add(colVal);
                     else 
                        //判断属性是否存在
                        Object col = ReflectionUtil.getFiled(entry.getValue().get(0), colName);
                        if (col == null) 
                            obj.add(entry.getKey());
                         else 
                            //属性存在,则取值
                            Object colVal = ReflectionUtil.getFiledValue(entry.getValue().get(0), colName);
                            obj.add(colVal);
                        
                    
                
                //计算count 标签
                else if (colName.toLowerCase().replace(" ", "").startsWith("count(".toLowerCase())) 
                    String countName = colName.substring("count(".length(), colName.indexOf(")"));
                    String[] args = countName.split(",");
                    //如果args>1,说明有条件
                    if (args.length > 1) 
                        //获取多个条件
                        String[] argsArr = args[0].split("\\\\|");
                        Supplier<Stream<T>> st = ()->entry.getValue().stream();
                        for (String argsSimple : argsArr) 
                            Supplier<Stream<T>> stFilter = st;
                            //获取单个条件,拼接
                            String[] argsKV;
                            if (argsSimple.indexOf("!:") > 0) 
                                //不等
                                argsKV = argsSimple.split("!:");
                                st = () ->stFilter.get()
                                        .filter(x -> !(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]));
                             else 
                                //相等
                                argsKV = argsSimple.split(":");
                                st = () -> stFilter.get()
                                        .filter(x -> (ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]));
                            

                        
                        Object colVal = st.get().collect(Collectors.toList()).size();
                        obj.add(colVal);
                     else 
                        Object colVal = entry.getValue().size();
                        obj.add(colVal);
                    

                
                //计算countDistinct标签
                else if (colName.toLowerCase().replace(" ", "").startsWith("countDistinct(".toLowerCase())) 
                    String countName = colName.substring("countDistinct(".length(), colName.indexOf(")"));
                    String[] args = countName.split(",");
                    //如果args>1,说明有条件
                    if (args.length > 1) 
                        //获取多个条件
                        String[] argsArr = args[0].split("\\\\|");
                        Supplier<Stream<Object>> st = ()-> (Stream<Object>) entry.getValue().stream();
                        for (String argsSimple : argsArr) 
                            Supplier<Stream<Object>> stFilter = st;
                            //获取单个条件,拼接
                            String[] argsKV;
                            //不等
                            if (argsSimple.indexOf("!:") > 0) 
                                argsKV = argsSimple.split("!:");
                                st = () -> stFilter.get()
                                        .filter(x -> !(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]))
                                        .map(x -> ReflectionUtil.getFiledValue(x, args[1]))
                                        .distinct();
                             else 
                                //相等
                                argsKV = argsSimple.split(":");
                                st = () -> stFilter.get()
                                        .filter(x -> (ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]))
                                        .map(x -> ReflectionUtil.getFiledValue(x, args[1]))
                                        .distinct();
                            

                        
                        Object colVal = st.get().collect(Collectors.toList()).size();
                        obj.add(colVal);
                     else 
                        Object colVal = entry.getValue().stream()
                                .map(x -> ReflectionUtil.getFiledValue(x, args[0]))
                                .distinct()
                                .collect(Collectors.toList()).size();
                        obj.add(colVal);
                    

                
                //计算sum 标签
                else if (colName.toLowerCase().replace(" ", "").startsWith("sum(".toLowerCase())) 
                    String sumName = colName.substring("sum(".length(), colName.indexOf(")"));
                    String[] args = sumName.split(",");
                    //如果args>1,说明有条件
                    if (args.length > 1) 
                        //获取多个条件
                        String[] argsArr = args[0].split("\\\\|");
                        Supplier<Stream<T>> st = ()->entry.getValue().stream();
                        for (String argsSimple : argsArr) 
                            Supplier<Stream<T>> stFilter = st;
                            //获取单个条件,拼接
                            String[] argsKV;
                            //不等
                            if (argsSimple.indexOf("!:") > 0) 
                                argsKV = argsSimple.split("!:");
                                st = () -> stFilter.get()
                                        .filter(x -> !(ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]));
                             else 
                                //相等
                                argsKV = argsSimple.split(":");
                                st = () -> stFilter.get()
                                        .filter(x -> (ReflectionUtil.getFiledValue(x, argsKV[0]) == null ? "null" : ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]));
                            
                        
                        Object 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);
                        obj.add(colVal);
                     else 
                        Object colVal = entry.getValue().stream()
                                .map(x -> new BigDecimal(ReflectionUtil.getFiledValue(x, args[0]) == null ? "0" : ReflectionUtil.getFiledValue(x, args[0]).toString()))
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                        obj.add(colVal);
                    

                
                //计算列
                else 
                    Object colVal = entry.getValue().stream()
                            .map(x -> new BigDecimal(ReflectionUtil.getFiledValue(x, colName) == null ? "0" : ReflectionUtil.getFiledValue(x, colName).toString().replace(",", "")))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    obj.add(colVal);

                
            
            //添加到data
            data.add(obj);
        

        //默认按照第一列排序
        data.sort(comparing(x -> (x.get(0) == null ? "" : x.get(0).toString())));
        return data;
    

总计列

/**
     * 添加合计列
     *
     * @param fieldNames          字段
     * @param data                数据
     * @param calculateHeadsNames 计算列
     * @return
     */
    public List<Object> addTotal(List<String> fieldNames, List<List<Object>> data, List<String> calculateHeadsNames) 
        List<Object> totalLine = new ArrayList<>();
        try 
            //按照数据的长度,初始化大小
            if (data.size() > 0) 
                data.get(0).forEach(x -> totalLine.add(""));
                //增加TOTAL字样
                totalLine.set(0, "TOTAL");
                //计算列
                if (calculateHeadsNames != null && calculateHeadsNames.size() > 0) 
                    for (String colName : calculateHeadsNames) 
                        Integer index = fieldNames.indexOf(colName);
                        if (index > -1) 
                            BigDecimal val = data.stream().map(x -> new BigDecimal(x.get(index) == null ? "0" : x.get(index).toString()))
                                    .reduce(BigDecimal::add).get();
                            totalLine.set(index, val);
                        
                    
                
            
            return totalLine;
         catch (Exception e) 
            e.printStackTrace();
         finally 
            return totalLine;
        
    

三,测试

@Test
    public void testLambda() throws NoSuchFieldException, IllegalAccessException 

        List<MyTest> list=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<MyTest> rList = report.getDataListFilter(list, reportArgsReq.getEqualsMap(),reportArgsReq.getNotEqualsMap());
        Map<String,List<MyTest>> rMap=report.getDataListGroup(rList,reportArgsReq.getFieldGroups());
        System.out.println(rMap.size());
//        List<FileTypeVO> 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,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"],
    "calcRatioHeads": ["TEU","AIR Bill","LCL Bill","jobProfit"],
    "groupReportList": ["jobName","pol","pod"]
  


解释:

字段

注释

equalsMap需要过滤的相等字段。
notEqualsMap需要过滤的不等字段。
fieldGroups分组字段。
headsExcel写入excel的表头
fieldNames使用到的字段,对应到表头。
calculateFieldNames
需要计算的字段,int,decimal,非数值类型(Count).....

sum(type:SEA|mode:FCL,TEU) : 计算type为sea,并且mode为FCL 的TEU 总和

count(type:AIR,shipmentID):计算type为Air,的shipment数量

jobProfit / sum(jobProfit):同样的含义,直接计算jobProfit的总合

countDistinct(type:AIP,shipmentID):去重后计算count

以上是关于java 动态 Lambda的主要内容,如果未能解决你的问题,请参考以下文章

java 动态 lambda

java 动态 lambda

Java lambda 动态查询

Java lambda 动态查询

Java lambda 动态查询

Java JVM 动态方法调用指令 invokedynamic 实现分析(以 Lambda 表达式实现原理为例)...