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

/**
     * 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) 
        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())));
            
        
        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())));
            
        
        List<T> rList = st.get().collect(Collectors.toList());
        return rList;
    

    /**
     * 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)) 
                    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 =null;
                        for(String argsSimple : argsArr)
                            //获取单个条件,拼接
                            String[] argsKV;
                            if(argsSimple.indexOf("!:")>0)
                            
                                //不等
                                argsKV=argsSimple.split("!:");
                                st = ()-> entry.getValue().stream()
                                        .filter(x->!(ReflectionUtil.getFiledValue(x, argsKV[0])==null?"null":ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]));
                            
                            else 
                                //相等
                                argsKV = argsSimple.split(":");
                                st = ()-> entry.getValue().stream()
                                        .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 =null;
                        for(String argsSimple : argsArr)
                            //获取单个条件,拼接
                            String[] argsKV;
                            //不等
                            if(argsSimple.indexOf("!:")>0) 
                                argsKV = argsSimple.split("!:");
                                st =()-> entry.getValue().stream()
                                        .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 =()-> entry.getValue().stream()
                                        .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 =null;
                        for(String argsSimple : argsArr)
                            //获取单个条件,拼接
                            String[] argsKV;
                            //不等
                            if(argsSimple.indexOf("!:")>0) 
                                argsKV = argsSimple.split("!:");
                                st = () -> entry.getValue().stream()
                                        .filter(x -> !(ReflectionUtil.getFiledValue(x, argsKV[0])==null?"null":ReflectionUtil.getFiledValue(x, argsKV[0]).toString()).equals(argsKV[1]));
                            
                            else 
                                //相等
                                argsKV = argsSimple.split(":");
                                st = () -> entry.getValue().stream()
                                        .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);
        

        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 的主要内容,如果未能解决你的问题,请参考以下文章

Android开发太难了:Java Lambda ≠ Android Lambda (上)

Android开发太难了:Java Lambda ≠ Android Lambda (上)

Android开发太难了:Java Lambda ≠ Android Lambda (上)

java 动态 Lambda

java 动态 Lambda

JAVA由一个将JSONArray转成Map的需求引发的lambda语法的学习