结论
| 名称 | 支持高精度 | 测试版本 | 说明 |
|---|---|---|---|
| Ognl | 是 | 3.2.18 | ognl <= 2.7.1 版本存在问题 注(1) |
| Jexl | 是 | 3.1 | |
| MVEL | 是 | 2.4.12.Final | |
| JEPLite | 否 | 0.8.7a | addVariable方法只支持double变量 |
| JEval | 否 | 0.9.4 | 变量要用#{x};putVariable方法只支持string(转换为double计算) |
| Janino | 否 | 2.5.10 | 变量值是BigDecimal时报错 |
注(1):ognl 版本问题
计算 “a<=-0.1”,当 a = new BigDecimal(“-0.1”) 时,本应返回true,但是 ognl <= 2.7.1 版本返回false
测试代码
import java.io.Serializable;import java.math.BigDecimal;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import org.apache.commons.jexl3.JexlContext;import org.apache.commons.jexl3.JexlEngine;import org.apache.commons.jexl3.JexlExpression;import org.apache.commons.jexl3.MapContext;import org.apache.commons.jexl3.internal.Engine;import org.cheffo.jeplite.JEP;import org.codehaus.janino.ExpressionEvaluator;import org.mvel2.MVEL;import com.gitee.qdbp.tools.utils.OgnlTools;import net.sourceforge.jeval.Evaluator;public class ExpressionTest {public static void main(String[] args) throws Exception {String content = "x-y";Map<String, BigDecimal> map = new HashMap<>();map.put("x", new BigDecimal("0.9"));map.put("y", new BigDecimal("1"));{ // Java精度问题: 0.9-1=-0.09999999999999998double result = 0.9 - 1;System.out.printf("%-10s %s%n", "Java:", result);}{ // Ognl支持BigDecimal: 0.9-1=-0.1Object result = OgnlTools.getValue(map, content);System.out.printf("%-10s %s%n", "Ognl:", result);}{ // Jexl支持BigDecimal: 0.9-1=-0.1JexlContext context = new MapContext();for (Entry<String, BigDecimal> entry : map.entrySet()) {context.set(entry.getKey(), entry.getValue());}JexlEngine engine = new Engine();JexlExpression expression = engine.createExpression(content);Object result = expression.evaluate(context);System.out.printf("%-10s %s%n", "Jexl:", result);}{ // MVEL支持BigDecimal: 0.9-1=-0.1Serializable expression = MVEL.compileExpression(content);Object result = MVEL.executeExpression(expression, map);System.out.printf("%-10s %s%n", "MVEL:", result);}{ // JEPLite只支持double: 0.9-1=-0.09999999999999998JEP jep = new JEP();for (Entry<String, BigDecimal> entry : map.entrySet()) {jep.addVariable(entry.getKey(), entry.getValue().doubleValue());}jep.parseExpression(content);Object result = jep.getValue();System.out.printf("%-10s %s%n", "JEPLite:", result);}{ // JEval表达式中的变量要用#{x}, 变量值只支持string, 会转换为double计算, 导致精度误差String string = "#{x}-#{y}";Evaluator evaluator = new Evaluator();for (Entry<String, BigDecimal> entry : map.entrySet()) {if (entry.getValue() != null) {evaluator.putVariable(entry.getKey(), String.valueOf(entry.getValue()));}}Object result = evaluator.evaluate(string);System.out.printf("%-10s %s%n", "JEval:", result);}{ // Janino不支持BigDecimal计算: 0.9-1=-0.09999999999999998List<String> keys = new ArrayList<>();List<Object> values = new ArrayList<>();List<Class<?>> types = new ArrayList<>();for (Entry<String, BigDecimal> entry : map.entrySet()) {if (entry.getValue() != null) {keys.add(entry.getKey());values.add(entry.getValue().doubleValue());types.add(double.class);}}ExpressionEvaluator evaluator = new ExpressionEvaluator();evaluator.setParameters(keys.toArray(new String[0]), types.toArray(new Class<?>[0]));evaluator.cook(content);Object result = evaluator.evaluate(values.toArray());System.out.printf("%-10s %s%n", "Janino:", result);}}}
涉及到的jar包
<dependency><groupId>ognl</groupId><artifactId>ognl</artifactId><version>3.2.18</version></dependency><dependency><groupId>net.sourceforge.jeval</groupId><artifactId>jeval</artifactId><version>0.9.4</version></dependency><dependency><groupId>org.cheffo</groupId><artifactId>jeplite</artifactId><version>0.8.7a</version></dependency><dependency><groupId>janino</groupId><artifactId>janino</artifactId><version>2.5.10</version></dependency><dependency><groupId>org.mvel</groupId><artifactId>mvel2</artifactId><version>2.4.12.Final</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-jexl3</artifactId><version>3.1</version></dependency>
