结论
名称 | 支持高精度 | 测试版本 | 说明 |
---|---|---|---|
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.09999999999999998
double result = 0.9 - 1;
System.out.printf("%-10s %s%n", "Java:", result);
}
{ // Ognl支持BigDecimal: 0.9-1=-0.1
Object result = OgnlTools.getValue(map, content);
System.out.printf("%-10s %s%n", "Ognl:", result);
}
{ // Jexl支持BigDecimal: 0.9-1=-0.1
JexlContext 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.1
Serializable expression = MVEL.compileExpression(content);
Object result = MVEL.executeExpression(expression, map);
System.out.printf("%-10s %s%n", "MVEL:", result);
}
{ // JEPLite只支持double: 0.9-1=-0.09999999999999998
JEP 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.09999999999999998
List<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>