本文主要是介绍Aviator 一种表达式求值引擎,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.简介
Aviator是一个高性能、轻量级的 java 语言实现的表达式求值引擎, 主要用于各种表达式的动态求值。现在已经有很多开源可用的 java 表达式求值引擎,为什么还需要 Avaitor 呢?
Aviator的设计目标是轻量级和高性能,相比于Groovy、JRuby的笨重, Aviator非常小, 加上依赖包也才 537K,不算依赖包的话只有 70K; 当然, Aviator的语法是受限的, 它不是一门完整的语言, 而只是语言的一小部分集合。
其次, Aviator的实现思路与其他轻量级的求值器很不相同, 其他求值器一般都是通过解释的方式运行, 而Aviator则是直接将表达式编译成 JVM 字节码, 交给 JVM 去执行。简单来说, Aviator的定位是介于 Groovy 这样的重量级脚本语言和 IKExpression 这样的轻量级表达式引擎之间。
2.特性
Aviator的特性:
- 支持绝大多数运算操作符,包括算术操作符、关系运算符、逻辑操作符、位运算符、正则匹配操作符(=~)、三元表达式(? : );
- 支持操作符优先级和括号强制设定优先级;
- 逻辑运算符支持短路运算;
- 支持丰富类型,例如nil、整数和浮点数、字符串、正则表达式、日期、变量等,支持自动类型转换;
- 支持传入变量,支持类似a.b.c的嵌套变量访问;
- 内置一套强大的常用函数库;
- 可自定义函数,易于扩展;
- 可重载操作符;
- 支持大数运算(BigInteger)和高精度运算(BigDecimal);
- 性能优秀。
Aviator的限制:
- 没有if else、do while等语句,没有赋值语句,仅支持逻辑表达式、算术表达式、三元表达式和正则匹配。
- 无法自定义运算符,自定义函数有局限性
3.依赖
Aviator依赖了commons-beanutils, 使用Aviator可以添加下面的maven依赖:
<dependency><groupId>com.googlecode.aviator</groupId><artifactId>aviator</artifactId><version>{version}</version></dependency>
从 3.2.0 版本开始, Aviator 仅支持 JDK 7 及其以上版本。 JDK 6 请使用 3.1.1 这个稳定版本。
4.使用手册
- 执行表达式
Aviator的使用都是集中通过com.googlecode.aviator.AviatorEvaluator这个入口类来处理, 最简单的例子, 执行一个计算1+2+3的表达式:
val result = AviatorEvaluator.execute("1+2+3")
println(result) //6
如果开启了 ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL 选项,那么在表达式中出现的浮点数都将解析为 BigDecimal,这是为了方便一些用户要求高精度的计算,又不想额外地给浮点数加上 M 后缀标记为 BigDecimal:
AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true)
- 多行表达式
从 4.0.0 开始, aviator支持以分号 ; 隔开的多行表达式,对于多行表达式求值的结果将是最后一个表达式的结果,例如
val result = AviatorEvaluator.execute("println('hello world'); 1+2+3 ; 100-1")
println(result)
//输出结果:
//hello world
//99
表达式的结果将是最后一个表达式 100-1,也就是 99,但是中间的表达式也将执行,包括打印 hello world。通过在表达式求值过程中加入 println打印,可以方便调试,也可以通过 Options.TRACE_EVAL来跟踪执行过程,参见后续章节。
- 求值器多实例
AviatorEvaluator是一个全局静态实例,但是很多场景下,你可能想为不同的场景提供一个不同的求值器实例,包括不同的选项配置和自定义函数列表等,那么从 4.0.0开始, Aviator提供了多实例的求值器支持:
val instance = AviatorEvaluator.newInstance
//接下来使用 instance,几乎跟 AviatorEvaluator 没有不同,只是换成了实例方法
- 使用变量
下面的例子演示了怎么向表达式传入变量值, 表达式中的world是一个变量, 默认为null, 通过传入Map<String,Object>的变量绑定环境, 将world设置为“world”。 env 的key是变量名, value是变量的值。
val world = "world"
val env = new util.HashMap[String,Object]()
env.put("world",world)
val result =AviatorEvaluator.execute(" 'hello ' + world ",env)
println(result) // hello world
'hello ‘是一个Aviator的String, Aviator的String是任何用单引号或者双引号括起来的字符序列, String可以比较大小(基于unicode顺序), 可以参与正则匹配, 可以与任何对象相加, 任何对象与String相加结果为String。 String中也可以有转义字符,如\n、\、’ 等。
AviatorEvaluator.execute(" 'a\"b' ") // 字符串 a"b
AviatorEvaluator.execute(" \"a\'b\" ") // 字符串 a'b
AviatorEvaluator.execute(" 'hello ' + 3 ") // 字符串 hello 3
AviatorEvaluator.execute(" 'hello '+ unknow ") // 字符串 hello null
- exec 方法
Aviator 2.2 开始新增加一个exec方法, 可以更方便地传入变量并执行, 而不需要构造env这个map了:
val value = "world"
AviatorEvaluator.exec("'hello' + value",value) // hello world
- 调用函数
Aviator 支持函数调用, 函数调用的风格类似 lua, 下面的例子获取字符串的长度:
AviatorEvaluator.execute("string.length('hello')")
string.length(‘hello’)是一个函数调用, string.length是一个函数, 'hello’是调用的参数。
再用string.substring来截取字符串:
AviatorEvaluator.execute("string.contains(\"test\", string.substring('hello', 1, 2))") // true
通过string.substring(‘hello’, 1, 2)获取字符串’e’, 然后通过函数string.contains判断e是否在’test’中。可以看到, 函数可以嵌套调用。
- 自定义函数
Aviator除了内置的函数之外,还允许用户自定义函数,只要实现com.googlecode.aviator.runtime.type.AviatorFunction接口, 并注册到AviatorEvaluator即可使用. AviatorFunction接口十分庞大, 通常来说你并不需要实现所有的方法, 只要根据你的方法的参数个数, 继承AbstractFunction类并override相应方法即可。
这篇关于Aviator 一种表达式求值引擎的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!