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); }
调用示例