Java动态计算

公式的解析和参数设置.有两个选择 . 一个是引用apache下的commons-jexl包.用其中的包装好的方法 . 一个是用jdk中原生的scriptEngine引擎实现 . 

一 . commons-jexl包使用

pom包引用

<dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-jexl3</artifactId>
      <version>3.1</version>
</dependency> 

 工具方法如下 : 

/**
     * jexlEngine引擎执行公式计算
     * @param jexExp 公式 . 如 (a+b-c)*d/f
     * @param reflectParamMap 参数集合
     * @return 返回结果默认String
     * @throws Throwable
     */
    public static String calWithJexlEngine(String jexExp ,
                                           Map<String , Object> reflectParamMap) throws Throwable{
        JexlEngine engine = new Engine();
        JexlExpression expression = engine.createExpression(jexExp);
        JexlContext jc = new MapContext();

        reflectParamMap.keySet().forEach(k->{
            //jexl计算结果类型根据入参决定:
            //如果参数都是int/Integer类型 . 那么即便结果值应该是4.8 . 返回值也是4 .所以这里为保证计算精度 . 入参可全部以decimal类型处理下
            //若参数中存在小数,则结果精度相对准确 . 出参为double类型
            Object paramVal = reflectParamMap.get(k);
            String paramValStr = paramVal != null ? String.valueOf(paramVal) : "0";
            jc.set(k , new BigDecimal(paramValStr));
        });
        Object result =expression.evaluate(jc);
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        return decimalFormat.format(result);
    }

二.jdk中scriptEngine引擎执行计算

/**
     * jdk的ScriptEngine引擎执行公式计算
     * @param jexExp 公式 . 如 (a+b-c)*d/f   或者是带判断的函数表达式 : if(a == 1) b*(c+2)/d;
     * @param reflectParamMap 参数集合
     * @param paramScope 参数范围
     * @return
     */
    public static String calWithScriptEngine(String jexExp ,
                                           Map<String , Object> reflectParamMap ,
                                           Integer paramScope) throws Throwable{
        ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("js");
        Bindings bindings = scriptEngine.createBindings();
        bindings.putAll(reflectParamMap);
        paramScope = paramScope != null ? paramScope : ScriptContext.ENGINE_SCOPE;
        scriptEngine.setBindings(bindings , paramScope);
        //出参默认为double类型的 . 入参类型对结果精度无影响
        Object result = scriptEngine.eval(jexExp);
        //保留两位小数
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        return decimalFormat.format(result);
    }

 

调用示例

 

posted @ 2022-05-14 00:41  每天学习1点点  阅读(1117)  评论(0编辑  收藏  举报