工作中使用 栈结构( stack ) 的例子汇总( 持续更新... )

1. QLExpress 中使用 stack 解决函数参数个数和参数类型合法性校验错误提示:

   如果公式有问题,QLExpress 默认只是报错,并且是很没有规律的原始的错误信息,靠解析错误信息给页面提示不太可行,发现QLExpress 有

一个获取表达式指令集合的 api,是以前缀表达式格式顺序存储的,即假设角标 i 处存储的是一个 两数相加的 函数指令,则 i-1、i-2处存储的就是该加法指令

的两个参数( 如果表达式正确的话 ),只需要定义一个栈,然后遍历 该指令集合,遇到 操作数( 变量 和 常量 ) 指令 就压栈,遇到 函数指令根据 函数的类型决定从 栈顶

弹出 指定个数据,判断函数的类型 和  个数,做出相应错误提示

import com.ql.util.express.InstructionSet;
import com.ql.util.express.OperateData;
import com.ql.util.express.instruction.detail.Instruction;
import com.ql.util.express.instruction.detail.InstructionCallSelfDefineFunction;
import com.ql.util.express.instruction.detail.InstructionConstData;
import com.ql.util.express.instruction.detail.InstructionLoadAttr;
import com.ql.util.express.instruction.detail.InstructionOperator;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Stack;

@Slf4j
@Component
public class FormulaExpressionValidateService {

    @Getter
    @Setter
    public static class MyOperateData {

        public static final Double DOUBLE_CONST_VALUE = 1.1d;
        public static final Integer INTEGER_CONST_VALUE = 1;
        public static final String STRING_CONST_VALUE = "string";
        public static final Boolean BOOLEAN_CONST_VALUE = true;

        public static final String CONST_VALUE_TYPE_DOUBLE = "double"; // double 类型常量
        public static final String CONST_VALUE_TYPE_INTEGER = "integer"; //int类型常量
        public static final String CONST_VALUE_TYPE_STRING = "string";  // String类型常量
        public static final String CONST_VALUE_TYPE_BOOLEAN = "boolean"; // 布尔类型常量

        private String attrName; // dataType 如果是属性名,则 attrName  表示的是 属性名称的值
        private String constValueType; //dateType  如果是  常量,则 constValueType 表示的是常量的类型( double、integer、string、boolean )
    }

    @Autowired
    private  QLExpressRunner qlExpressRunner;
    // todo  检测是否 有  pop 的参数 顺序弄反的地方!!!!

    /**
     * 校验 表达式是否合法
     * @param express
     * @return
     */
    public String verifyFormulaExpress( String express ){
        if( StringUtils.isBlank( express ) ){
            return "公式不能为空";
        }
        InstructionSet instructionSet = this.qlExpressRunner.parseInstructionSet(express);
        if( instructionSet == null ){
            return null;
        }

        // 校验每个函数的参数长度是否合法
        String illegalMessage = this.verityFunctionArgsSize( instructionSet );
        if( illegalMessage != null ){
            return illegalMessage;
        }

        // 校验每个函数的参数类型是否合法
        return this.verityFunctionArgsType( instructionSet );
    }

    private String verityFunctionArgsType(InstructionSet instructionSet) {
        // 遇到 属性参数( 比如 LCOE1、PIRR、LCOE )  和 常量参数( 比如: 1、100、'Y'、'A' )
        // 遇到 加减乘除 操作符等
        // 遇到自定义函数,从栈顶取出需要的 参数,检测类型,如果类型不对则报错,然后将计算结果压栈( 其实是假计算,压一个和该函数返回值类型相同的样本数据 )
        int instructionLength = instructionSet.getInstructionLength();
        Stack stack = new Stack<>();
        String errorMessage = null;
        for( int i = 0;i < instructionLength;i++ ){
            Instruction instruction = instructionSet.getInstruction( i );
            if( instruction instanceof InstructionLoadAttr){
                // 属性名,如  LCOE1
                InstructionLoadAttr instructionLoadAttr = (InstructionLoadAttr) instruction;
                String attrName = instructionLoadAttr.getAttrName();
                MyOperateData myOperateData = new MyOperateData();
                myOperateData.setAttrName( attrName );
                stack.push( myOperateData );
            }else if( instruction instanceof InstructionConstData){
                // 常量,如 1,100, 'Y','A','true','false'
                InstructionConstData instructionConstData = (InstructionConstData) instruction;
                OperateData operateData = instructionConstData.getOperateData();
                Class orgiType = operateData.getOrgiType();// double  字符串  布尔
                MyOperateData myOperateData = new MyOperateData();
                // todo  测试是否只有这几种类型
                if( orgiType == Double.class || orgiType == BigDecimal.class ){
                    myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
                }else if( orgiType == Boolean.class ){
                    myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
                }else if( orgiType == String.class ){
                    myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_STRING );
                }else if( orgiType == Integer.class ){
                    myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_INTEGER );
                }
                stack.push( myOperateData );
            }else if( instruction instanceof InstructionOperator){
                InstructionOperator instructionOperator = (InstructionOperator) instruction;
                String operatorName = instructionOperator.getOperator().getName();
                if( "+".equals( operatorName ) ||
                        "-".equals( operatorName ) ||
                        "*".equals( operatorName ) ||
                        "/".equals( operatorName ) ){
                    errorMessage = this.validateAddSubMultiDivideOperates( operatorName,stack,"double" );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }
                if( ">".equals( operatorName ) ||
                        ">=".equals( operatorName ) ||
                        "<".equals( operatorName ) ||
                        "<=".equals( operatorName ) ||
                        "==".equals( operatorName ) ){
                    errorMessage = this.validateCompareOperates( operatorName,stack );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }
                if( "IF".equals( operatorName ) ){
                    errorMessage = this.validateIfFunctions( operatorName,stack );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }
                if( "AND".equals( operatorName ) ){
                    try{
                        Field opDataNumberField = InstructionOperator.class.getDeclaredField("opDataNumber");
                        opDataNumberField.setAccessible( true );
                        // 该函数实际传递的参数个数
                        Integer argSize = (Integer) opDataNumberField.get(instructionOperator);
                        errorMessage = this.validateAndFunctions( argSize,operatorName,stack );
                        if( errorMessage == null ){
                            continue;
                        }
                        break;
                    }catch ( Exception e ){
                        e.printStackTrace();
                        return "函数 AND 的参数有问题";
                    }
                }

                if( "ROUND_UP".equals( operatorName ) || "ROUND_DOWN".equals( operatorName ) || "ROUND".equals( operatorName ) ){
                    errorMessage = this.validateRoundUpRoundDownRoundFunctions( operatorName,stack );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }

                if( "ABS".equals( operatorName ) || "INT".equals( operatorName ) ){
                    errorMessage = this.validateAbsIntFunctions( operatorName,stack );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }
                if( "MAX".equals( operatorName ) ||
                        "MIN".equals( operatorName ) ||
                        "SUM".equals( operatorName ) ||
                        "AVERAGE".equals( operatorName ) ){
                    errorMessage = this.validateMaxMinSumAverageFunctions( operatorName,stack );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }

                //  todo  对于 多个参数的 函数 貌似 参数顺序取反了?????
                if( "RANK".equals( operatorName ) ){
                    errorMessage = this.validateRankFunctions( operatorName,stack );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }
                if( "KSMALL".equals( operatorName ) ||
                        "KLARGE".equals( operatorName ) ){
                    errorMessage = this.validateKsmallKlargeFunctions( operatorName,stack );
                    if( errorMessage == null ){
                        continue;
                    }
                    break;
                }
            }
        }
        return errorMessage;
    }


    // 抽取一个 根据函数类型 和 返回值一样的公共方法
    /**
     * RANK( 三个参数,第一个为数字常量 或者  LCOE PIRR 等规定的几个 数字类型的属性,第二个 为 LCOE1 PIRR1 等规定的几个集合属性,第三个为1/2 )
     * @param functionName
     * @param stack
     * @return
     */
    private String validateRankFunctions(String functionName, Stack stack ) {
        // 第三个参数必须为 Integer  类型常量
        MyOperateData operateData = stack.pop();
        String constValueType = operateData.getConstValueType();
        if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
            return "函数 " + functionName + " 的第三个参数必须为整数";
        }

        // 第二个参数必须为 double 集合 类型 属性名
        operateData = stack.pop();
        String attrName = operateData.getAttrName();
        if( attrName == null || !RuleTempServiceImpl.doubleCollectionAttrNames.contains( attrName ) ){
            return "函数 " + functionName + " 第二个参数必须为 " + RuleTempServiceImpl.doubleCollectionAttrNames.toString() + " 之一";
        }

        // 第一个参数必须为  Double 类型常量  或  double  类型属性名
        operateData = stack.pop();
        attrName = operateData.getAttrName();
        if( attrName == null ){
            constValueType = operateData.getConstValueType();
            if( !( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ) ){
                return "函数 " + functionName + " 第一个参数必须为一个数字 或者 可选属性 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 中的其一";
            }
        }else {
            if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
                return "函数 " + functionName + " 第一个参数必须为一个数字 或者 可选属性 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 中的其一";
            }
        }

        //压栈一个 Integer  常量
        operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_INTEGER );
        stack.push( operateData );
        return null;
    }

    /**
     * KSMALL、KLARGE( 2个参数,第一个 为 LCOE1 PIRR1 等规定的几个集合属性,第二个为 数字 )
     * @param functionName
     * @param stack
     * @return
     */
    private String validateKsmallKlargeFunctions(String functionName, Stack stack) {
        // 第二个参数必须为 Integer  常量
        MyOperateData operateData = stack.pop();
        String constValueType = operateData.getConstValueType();
        if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
            return "函数 " + functionName + " 的第二个参数必须为整数";
        }

        // 第一个参数必须为 double 类型的集合属性
        operateData = stack.pop();
        String attrName = operateData.getAttrName();
        if( attrName == null || !RuleTempServiceImpl.doubleCollectionAttrNames.contains( attrName ) ){
            return "函数 " + functionName + " 的第一个参数的可选值为 " + RuleTempServiceImpl.doubleCollectionAttrNames.toString() + " 之一";
        }

        // 压栈一个  doule  类型的常量
        operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
        stack.push( operateData );
        return null;
    }

    /**
     * ROUND_UP 、ROUND_DOWN、ROUND 函数( 2个参数,第一个为数据类型,第二个为整数类型 )
     * @param functionName
     * @param stack
     * @return
     */
    private String validateRoundUpRoundDownRoundFunctions(String functionName, Stack stack) {
        //第二个参数必须为 integer 常量
        MyOperateData operateData = stack.pop();
        String constValueType = operateData.getConstValueType();
        if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
            return "函数 " + functionName + " 的第二个参数类型必须为整数类型";
        }

        //第一个参数必须为 数字类型 的 属性 或者 常量
        operateData = stack.pop();
        String attrName = operateData.getAttrName();
        if( attrName == null ){
            constValueType = operateData.getConstValueType();
            if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
                return "函数 " + functionName + " 的第一个参数类型必须为数字类型";
            }
        }else {
            if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
                return "函数 " + functionName + " 的第一个参数类型必须为数字类型";
            }
        }

        //压栈 一个 double  类型常量
        operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
        stack.push( operateData );
        return null;
    }

    private String verityFunctionArgsSize(InstructionSet instructionSet ) {
        int instructionLength = instructionSet.getInstructionLength();
        if( instructionLength == 0 ){
            return null;
        }

        for( int i = 0;i < instructionLength; i++ ){
            Instruction instruction = instructionSet.getInstruction( i );
            if( instruction instanceof InstructionOperator){
                InstructionOperator instructionOperator = (InstructionOperator) instruction;
                Integer gotOpDataNumber = 0;
                try{
                    Field opDataNumberField = InstructionOperator.class.getDeclaredField("opDataNumber");
                    opDataNumberField.setAccessible( true );
                    // 该函数实际传递的参数个数
                    gotOpDataNumber = (Integer) opDataNumberField.get(instructionOperator);
                }catch ( Exception e ){
                    log.error( "Exception is ",e );
                }

                String currOperatorName = instructionOperator.getOperator().getName();
                // 该函数期望的 参数个数
                Integer expectedOpDataNumber = 0;
                if( RuleTempServiceImpl.selfFunctionNamesWith1Arg.contains( currOperatorName ) ){
                    expectedOpDataNumber = 1;
                }else if( RuleTempServiceImpl.selfFunctionNamesWith2Args.contains( currOperatorName ) ){
                    expectedOpDataNumber = 2;
                }else if( RuleTempServiceImpl.selfFunctionNamesWith3Args.contains( currOperatorName ) ){
                    expectedOpDataNumber = 3;
                }else if( "AND".equals( currOperatorName ) ){
                    if( gotOpDataNumber.intValue() < 2 ){
                        return "表达式不合法,函数 AND  期望 2 个以上参数,实际传递 " + gotOpDataNumber + " 个参数";
                    }
                    return null;
                }else if( RuleTempServiceImpl.baseOperatorNames.contains( currOperatorName ) ){
                    expectedOpDataNumber = 2;
                }

                if( !expectedOpDataNumber.equals( gotOpDataNumber ) ){
                     return "表达式不合法,函数 " + currOperatorName + "  期望 " + expectedOpDataNumber+ " 个参数,实际传递 " + gotOpDataNumber + " 个参数";
                }
            }else if( instruction instanceof InstructionCallSelfDefineFunction){
                // 未定义的函数,程序走到这 说明一定是用了 未定义的函数 ,直接报错
                InstructionCallSelfDefineFunction instructionCallSelfDefineFunction = (InstructionCallSelfDefineFunction) instruction;
                String functionName = instructionCallSelfDefineFunction.getFunctionName();
                return "表达式不合法,使用了未知函数 " + functionName;
            }
        }
        return null;
    }

    /**
     * MAX、MIN、SUM、AVERAGE( 一个参数 ,值为 LCOE1,PIRR1 等 要求的几个属性类型参数 )
     * @param functionName
     * @param stack
     * @return
     */
    private String validateMaxMinSumAverageFunctions( String functionName,Stack stack ){
        // 参数必须为 double  集合类型的 属性名称
        MyOperateData operateData = stack.pop();
        String attrName = operateData.getAttrName();
        if( attrName == null || !RuleTempServiceImpl.doubleCollectionAttrNames.contains( attrName ) ){
            return "函数 " + functionName + " 的参数可选值为 " + RuleTempServiceImpl.doubleCollectionAttrNames.toString() + " 之一";
        }

        // 压栈 一个 double  类型常量
        operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
        stack.push( operateData );
        return null;
    }


    /**
     * ABS、INT ( 一个参数,都为数字 )
     * @param functionName
     * @param stack
     * @return
     */
    private String validateAbsIntFunctions(String functionName,Stack stack ){
        // 参数必须为 数字类型的  常量 或 属性
        MyOperateData operateData = stack.pop();
        String attrName = operateData.getAttrName();
        if( attrName == null ){
            String constValueType = operateData.getConstValueType();
            if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
                return "函数 " + functionName + " 的参数必须为数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
            }
        }else{
            if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
                return "函数 " + functionName + " 的参数必须为数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
            }
        }
        // 压栈一个 double 类型常量
        operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
        stack.push( operateData );
        return null;
    }

    /**
     * IF  函数( 三个参数,第一个为布尔值,第二、三个为 数据类型 )
     * @param functionName
     * @param stack
     * @return
     */
    private String validateIfFunctions(String functionName,Stack stack ){
        //第三个参数必须为数字类型 常量 或 属性
        MyOperateData operateData = stack.pop();
        String attrName = operateData.getAttrName();
        if( attrName == null ){
            String constValueType = operateData.getConstValueType();
            if( !( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ) ){
                return "函数 IF 的第三个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
            }
        }else{
            if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
                return "函数 IF 的第三个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
            }
        }

        //第二个参数必须为数字类型 常量 或 属性(  todo  判断逻辑和 第三个参数的一模一样( 提示信息不一样 ),考虑重用 )
        operateData = stack.pop();
        attrName = operateData.getAttrName();
        if( attrName == null ){
            String constValueType = operateData.getConstValueType();
            if( !( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ) ){
                return "函数 IF 的第二个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
            }
        }else{
            if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
                return "函数 IF 的第二个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
            }
        }

        // 第一个参数必须为布尔常量
        operateData = stack.pop();
        String constValueType = operateData.getConstValueType();
        if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
            return "函数 IF 的第一个参数必须为一个布尔值";
        }

        //压栈 一个 double  类型常量
        operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
        stack.push( operateData );
        return null;
    }

    /**
     * AND 函数( 多于2个的布尔值 )
     * @param argSize
     * @param functionName
     * @param stack
     * @return
     */
    private String validateAndFunctions(Integer argSize,String functionName,Stack stack ){
        MyOperateData operateData = null;
        String constValueType = null;
        //参数类型 必去全为布尔常量
        for( int i = 0;i < argSize;i++ ){
            operateData = stack.pop();
            constValueType = operateData.getConstValueType();
            if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
                return "函数 AND 的参数必须是布尔类型";
            }
        }

        //压栈一个布尔类型常量
        operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
        stack.push( operateData );
        return null;
    }

    /**
     * 加减乘除操作符
     * @param operateName
     * @param stack
     * @return
     */
    private String validateAddSubMultiDivideOperates(String operateName, Stack stack, String resultType ){
        //第二个操作数必须是数字 类型的 常量 或者 属性
        MyOperateData operateData = stack.pop();
        String attrName = operateData.getAttrName();
        if( attrName == null ){
            String constValueType = operateData.getConstValueType();
            if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
                return "操作符 " + operateName + " 右边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
            }
        }else{
            if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
                return "操作符 " + operateName + " 右边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
            }
        }

        //第一个操作数必须是数字 类型的 常量 或者 属性( todo 和 前面一样 考虑重用 )
        operateData = stack.pop();
        attrName = operateData.getAttrName();
        if( attrName == null ){
            String constValueType = operateData.getConstValueType();
            if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
                return "操作符 " + operateName + " 左边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
            }
        }else{
            if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
                return "操作符 " + operateName + " 左边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
            }
        }

        // 压栈 一个 ${ resultType } 类型的常量
        operateData = new MyOperateData();
        if( "double".equals( resultType ) ){
            operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
        }else if( "boolean".equals( resultType ) ){
            operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
        }
        stack.push( operateData );
        return null;
    }

    /**
     * 比较运算操作符
     * @param operateName
     * @param stack
     * @return
     */
    private String validateCompareOperates(String operateName,Stack stack ){
        // 如果是大小比较 则两边必须是数字,和 加减乘除的一样
        if( !"==".equals( operateName ) ){
            return this.validateAddSubMultiDivideOperates( operateName,stack,"boolean" );
        }
        // 如果是等值比较 则两边可以是数字 也可以是字符串 ,但是必须一样

        MyOperateData operateData1 = stack.pop();
        String attrName1 = operateData1.getAttrName();

        MyOperateData operateData2 = stack.pop();
        String attrName2 = operateData2.getAttrName();

        // 第一个 和 第二个必须同时是字符串 或 数字
        String arg1Type = null; // "number" "string" "boolean" 分表表示数字 字符串 布尔值
        if( attrName1 == null ){
            String constValueType = operateData1.getConstValueType();
            if( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
                // 第一个是常量 数字
                arg1Type = "number";
            }else if( MyOperateData.CONST_VALUE_TYPE_STRING.equals( constValueType ) ){
                // 第一个是常量 字符串
                arg1Type = "string";
            }else if( MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
                // 第一个是常量 布尔值
                arg1Type = "boolean";
            }else{
                return "操作符 == 两边必须为 数字或字符串或布尔类型";
            }
        }else{
            if( RuleTempServiceImpl.doubleAttrNames.contains( attrName1 ) ){
                // 第一个是属性 数字
                arg1Type = "number";
            }else if( RuleTempServiceImpl.stringAttrNames.contains( attrName1 ) ){
                // 第一个是属性 字符串
                arg1Type = "string";
            }else{
                return "操作符 == 两边必须为 数字或字符串或布尔类型";
            }
        }

        // todo  和上面逻辑差不多 ,考虑重用
        String arg2Type = null; // "number" "string" "boolean" 分表表示数字 字符串 布尔值
        if( attrName2 == null ){
            String constValueType = operateData2.getConstValueType();
            if( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
                // 第一个是常量 数字
                arg2Type = "number";
            }else if( MyOperateData.CONST_VALUE_TYPE_STRING.equals( constValueType ) ){
                // 第一个是常量 字符串
                arg2Type = "string";
            }else if( MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
                // 第一个是常量 布尔值
                arg2Type = "boolean";
            }else{
                return "操作符 == 两边必须为 数字或字符串或布尔类型";
            }
        }else{
            if( RuleTempServiceImpl.doubleAttrNames.contains( attrName2 ) ){
                // 第一个是属性 数字
                arg2Type = "number";
            }else if( RuleTempServiceImpl.stringAttrNames.contains( attrName2 ) ){
                // 第一个是属性 字符串
                arg2Type = "string";
            }else{
                return "操作符 == 两边必须为 数字或字符串或布尔类型";
            }
        }

        if( arg1Type == null || arg2Type == null ){
            return "操作符 == 两边必须为 数字或字符串或布尔类型";
        }
        if( !arg1Type.equals( arg2Type ) ){
            return "操作符 == 两边必须同时为 数字或字符串或布尔类型";
        }

        //压栈 一个  布尔值类型的常量
        MyOperateData operateData = new MyOperateData();
        operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
        stack.push( operateData );
        return null;
    }
}

 

你可能感兴趣的:(算法,java8,java,栈,后端)