Aviator是一个高性能、轻量级的 java 语言实现的表达式求值引擎, 主要用于各种表达式的动态求值。现在已经有很多开源可用的 java 表达式求值引擎,为什么还需要 Avaitor 呢?
Aviator的设计目标是轻量级和高性能,相比于Groovy、JRuby的笨重, Aviator非常小, 加上依赖包也才 537K,不算依赖包的话只有 70K; 当然, Aviator的语法是受限的, 它不是一门完整的语言, 而只是语言的一小部分集合。
其次, Aviator的实现思路与其他轻量级的求值器很不相同, 其他求值器一般都是通过解释的方式运行, 而Aviator则是直接将表达式编译成 JVM 字节码, 交给 JVM 去执行。简单来说, Aviator的定位是介于 Groovy 这样的重量级脚本语言和 IKExpression 这样的轻量级表达式引擎之间。
Aviator 的特性
- 支持绝大多数运算操作符,包括算术操作符、关系运算符、逻辑操作符、位运算2.符、正则匹配操作符(=~)、三元表达式(?:)
- 支持操作符优先级和括号强制设定优先级
- 逻辑运算符支持短路运算。
- 支持丰富类型,例如nil、整数和浮点数、字符串、正则表达式、日期、变量等,支持自动类型转换。
- 内置一套强大的常用函数库
- 可自定义函数,易于扩展
- 可重载操作符
- 支持大数运算(BigInteger)和高精度运算(BigDecimal)
- 性能优秀
maven依赖
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>4.2.9</version>
</dependency>
使用
AviatorEvaluator是一个全局静态变量
Object obj = AviatorEvaluator.execute("123 + 4654");
System.out.println(obj);
结果
4777
Aviator的数值类型仅支持Long和Double, 任何整数都将转换成Long, 任何浮点数都将转换为Double, 包括传入的变量数值
//整数计算
Object obj = AviatorEvaluator.execute("123 + 4654");
System.out.println("123 + 4654 结果的类型:"+obj.getClass());
//小数计算
Object obj1 = AviatorEvaluator.execute("0.05+0.01");
System.out.println("0.05+0.01 结果的类型:"+obj1.getClass());
结果
123 + 4654 结果的类型:class java.lang.Long
0.05+0.01 结果的类型:class java.lang.Double
精度计算
开启 ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL 选项,那么在表达式中出现的浮点数都将解析为 BigDecimal
//未开启精度计算
Object obj1 = AviatorEvaluator.execute("0.05+0.01");
System.out.println("0.05+0.01 = " + obj1);
//精度计算
AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true);
Object obj2 = AviatorEvaluator.execute("0.05+0.01");
System.out.println("0.05+0.01 = " + obj2);
结果
0.05+0.01 = 0.060000000000000005
0.05+0.01 = 0.06
使用变量
Map<String,Object> map1 = new HashMap<>();
map1.put("field01","you ");
map1.put("field02","are ");
map1.put("field03","cool");
Object obj1 = AviatorEvaluator.execute("field01 + field02 + field03",map1);
System.out.println(obj1);
Map<String,Object> map2 = new HashMap<>();
map2.put("field01",100);
map2.put("field02",65);
map2.put("field03",35);
Object obj2 = AviatorEvaluator.execute("field01 + field02 + field03",map2);
System.out.println(obj2);
结果
you are cool
200
自定义函数
Aviator 除了内置的函数之外,还允许用户自定义函数,只要实现com.googlecode.aviator.runtime.type.AviatorFunction接口, 并注册到AviatorEvaluator即可使用.
-
AviatorFunction接口十分庞大, 通常来说你并不需要实现所有的方法, 只要根据你的方法的参 数个数, 继承AbstractFunction类并override相应方法即
image.png
public class AviService {
public static void main(String[] args) {
Map<String,Object> map2 = new HashMap<>();
map2.put("field01",100);
map2.put("field02",65);
AviatorEvaluator.addFunction(new AddFunction());
Object obj2 = AviatorEvaluator.execute("add(field01,field02)",map2);
System.out.println(obj2);
}
}
class AddFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
Number left = FunctionUtils.getNumberValue(arg1, env);
Number right = FunctionUtils.getNumberValue(arg2, env);
return new AviatorDouble(left.doubleValue() + right.doubleValue());
}
public String getName() {
return "add";
}
}
- 参数个数不确定,可以继承 AbstractVariadicFunction 类,只要实现其中的 variadicCall 方法即可
public class AviService {
public static void main(String[] args) {
Map<String, Object> map2 = new HashMap<>();
map2.put("field01", 100);
map2.put("field02", 65);
map2.put("field03", 35);
AviatorEvaluator.addFunction(new AddFunction());
Object obj2 = AviatorEvaluator.execute("add(field01,field02,field03)", map2);
System.out.println(obj2);
}
}
class AddFunction extends AbstractVariadicFunction {
public AviatorDouble variadicCall(Map<String, Object> env, AviatorObject... args) {
double i = 0;
for (AviatorObject arg : args) {
Object value = arg.getValue(env);
double v = Double.parseDouble(value.toString());
i = i + v;
}
return new AviatorDouble(i);
}
@Override
public String getName() {
return "add";
}
}
使用Java类方法作为自定义函数
从 4.2.2 开始, aviator 还提供了一个更便捷地批量将某个类的静态方法导入为自定义函数的方式
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException {
Map<String, Object> map2 = new HashMap<>();
map2.put("field01", "HELLO_WORD");
AviatorEvaluator.addStaticFunctions("ArStringUtil", ArStringUtil.class);
Object obj2 = AviatorEvaluator.execute("ArStringUtil.camelName(field01)", map2);
System.out.println(obj2);
map2.put("field02", 12345678);
Object obj3 = AviatorEvaluator.execute("ArStringUtil.number2Chinese(field02)", map2);
System.out.println(obj3);
}
结果
helloWord
一千二百三十四万五千六百七十八
- 支持导入实例方法
- 调用可变参数方法
- 批量导入方法和注解支持
- 重载运算符
编译表达式
public static void main(String[] args){
String rule = "field01 + field02";
Map<String, Object> map2 = new HashMap<>();
map2.put("field01", 1000);
map2.put("field02", 2000);
Expression compiledExp = AviatorEvaluator.compile(rule, true);
Object obj = compiledExp.execute(map2);
System.out.println(obj);
}
编译后的结果你可以自己缓存, 也可以交给 Aviator 帮你缓存, AviatorEvaluator内部有一个全局的缓存池, 如果你决定缓存编译结果, 可以通过:
public static Expression compile(java.lang.String expression, boolean cached)
三元运算符
map2.put("field01", 100);
String rule = "file01 > 200 ? '大于200' : '小于200'";
...
System.out.println(obj);//小于200
正则表达式
String rule = "field01 =~ /^[A-Z]+$/";
map2.put("field01", "ABC");
...
System.out.println(obj);//true
变量的语法糖
Map<String, Object> user = new HashMap<>();
user.put("name","张三");
user.put("age",18);
List<String> son = new ArrayList<>();
son.add("小明");
son.add("小方");
user.put("son",son);
map2.put("user",user);
String rule = "user.name + '的年龄是' + user.age + ',他的儿子是' + user.son[0] + '和' + user.son[1]";
//张三的年龄是18,他的儿子是小明和小方
nil 对象
nil是 Aviator 内置的常量,类似 java 中的null,表示空的值。nil跟null不同的在于,在 java 中null只能使用在==、!=的比较运算符,而nil还可以使用>、>=、<、<=等比较运算符。 Aviator 规定,任何对象都比nil大除了nil本身。用户传入的变量如果为null,将自动以nil替代。
AviatorEvaluator.execute("nil == nil"); //true
AviatorEvaluator.execute(" 3> nil"); //true
AviatorEvaluator.execute(" true!= nil"); //true
AviatorEvaluator.execute(" ' '>nil "); //true
AviatorEvaluator.execute(" a==nil "); //true, a 是 null
日期比较
Aviator 并不支持日期类型,如果要比较日期,你需要将日期写字符串的形式,并且要求是形如 “yyyy-MM-dd HH:mm:ss:SS”的字符串,否则都将报错。 字符串跟java.util.Date比较的时候将自动转换为Date对象进行比较:
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("2019-10-10");
Date date1 = new SimpleDateFormat("yyyy-MM-dd").parse("2019-10-10");
env.put("date", date);
env.put("date1", date1);
Object obj = AviatorEvaluator.execute("date == date1 ", env);
System.out.println(obj); // true
数据类型
- String 字符串类型,单引号或者双引号括起来的文本串
- 布尔值: 常量true和false
- 正则表达式, 以//括起来的字符串
- Number类型: 数字类型,支持四种类型,分别是long,double,java.math.BigInteger(简称 big int)和java.math.BigDecimal(简 称 decimal),规则如下:
任何以大写字母 N 结尾的整数都被认为是 big int
任何以大写字母 M 结尾的数字都被认为是 decimal
其他的任何整数都将被转换为 Long
其他任何浮点数都将被转换为 Double
超过 long 范围的整数字面量都将自动转换为 big int 类型
操作符
算术运算符
Aviator 支持常见的算术运算符,包括+ - * / %五个二元运算符,和一元运算符-(负)。其中- * / %和一元的-仅能作用于Number类型。
+不仅能用于Number类型,还可以用于String的相加,或者字符串与其他对象的相加。
Aviator 规定,任何类型与String相加,结果为String。
逻辑运算符
Avaitor 的支持的逻辑运算符包括,一元否定运算符!
,以及逻辑与的&&
,逻辑或的||
。逻辑运算符的操作数只能为Boolean
。
&&
和||
都执行短路规则。
关系运算符
Aviator 支持的关系运算符包括<, <=, >, >=
以及==
和!=
。
关系运算符可以作用于Number
之间、String
之间、Pattern
之间、Boolean
之间、变量之间以及其他类型与nil
之间的关系比较, 不同类型除了nil
之外不能相互比较。
位运算符
Aviator 支持所有的 Java 位运算符,包括&, |, ^, ~, >>, <<, >>>
。
匹配运算符
匹配运算符=~
用于String
和Pattern
的匹配,它的左操作数必须为String
,右操作数必须为Pattern
。 匹配成功后,Pattern
的分组将存于变量$num
,num
为分组索引。
三元运算符
Aviator 没有提供if else
语句,但是提供了三元运算符?:
,形式为bool ? exp1: exp2
。 其中bool
必须为Boolean
类型的表达式, 而exp1
和exp2
可以为任何合法的 Aviator 表达式,并且不要求exp1
和exp2
返回的结果类型一致。