简介?
Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢?
Aviator的设计目标是轻量级和高性能 ,相比于Groovy、JRuby的笨重,Aviator非常小,加上依赖包也才450K,不算依赖包的话只有70K;当然,Aviator的语法是受限的,它不是一门完整的语言,而只是语言的一小部分集合。
其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都是通过解释的方式运行,而Aviator则是直接将表达式编译成Java字节码,交给JVM去执行。简单来说,Aviator的定位是介于Groovy这样的重量级脚本语言和IKExpression这样的轻量级表达式引擎之间。
特性?
Aviator的特性
支持大部分运算操作符,包括算术操作符、关系运算符、逻辑操作符、正则匹配操作符(=~)、三元表达式?: ,并且支持操作符的优先级和括号强制优先级,具体请看后面的操作符列表。
支持函数调用和自定义函数
支持正则表达式匹配,类似Ruby、Perl的匹配语法,并且支持类Ruby的$digit指向匹配分组。
自动类型转换,当执行操作的时候,会自动判断操作数类型并做相应转换,无法转换即抛异常。
支持传入变量,支持类似a.b.c的嵌套变量访问。
性能优秀
Aviator的限制:
没有if else、do while等语句,没有赋值语句,仅支持逻辑表达式、算术表达式、三元表达式和正则匹配。
没有位运算符
整体结构?
Aviator的结构非常简单,一个典型的求值器的结构
依赖包?
commons-beanutils和commons-logging
使用手册?
执行表达式?
Aviator的使用都是集中通过com.googlecode.aviator.AviatorEvaluator这个入口类来处理,最简单的例子,执行一个计算1+2+3的表达式:
import com.googlecode.aviator.AviatorEvaluator;
public class SimpleExample {
public static void main(String【】 args) {
Long result = (Long) AviatorEvaluator.execute("1+2+3");
System.out.println(result);
}
}
细心的朋友肯定注意到结果是Long,而不是Integer。这是因为Aviator的数值类型仅支持Long和Double,任何整数都将转换成Long,任何浮点数都将转换为Double,包括用户传入的变量数值。这个例子的打印结果将是正确答案6。
使用变量?
想让Aviator对你say hello吗?很简单,传入你的名字,让Aviator负责字符串的相加:
import com.googlecode.aviator.AviatorEvaluator;
public class SayHello {
public static void main(String【】 args) {
if (args.length [span class="pln"> 1) {
System.err.print("Usesage: Java SayHello yourname");
}
String yourname = args【0】;
Map[span class="typ">String, ObjectString, Object
env.put("yourname", yourname);
String result = (String) AviatorEvaluator.execute(" 'hello ' + yourname ", env);
System.out.println(result);
}
}
上面的例子演示了怎么向表达式传入变量值,表达式中的yourname是一个变量,默认为null,通过传入Map的变量绑定环境,将yourname设置为你输入的名称。env的key是变量名,//代码效果参考:http://www.jhylw.com.cn/441837179.html
value是变量的值。上面例子中的'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
调用函数?
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))");
通过string.substring('hello',1,2)获取字符串'e',然后通过函数string.contains判断e是否在'test'中。可以看到,函数可以嵌套调用。
Aviator的内置函数列表请看后面。
自定义函数?
Aviator除了内置的函数之外,还允许用户自定义函数,只要实现com.googlecode.aviator.runtime.type.AviatorFunction接口,并注册到AviatorEvaluator即可使用
public interface AviatorFunction {
/
Get the function name
@return
/
public String getName();
/
call function
@param env
Variable environment
@param args
Function arguments
@return
/
public AviatorObject call(Map[span class="typ">String, Object
}
可以看一个例子,我们实现一个add函数来做数值的相加:
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorDouble;
import com.googlecode.aviator.runtime.type.AviatorFunction;
import com.googlecode.aviator.runtime.type.AviatorObject;
public class AddFunction implements AviatorFunction {
public AviatorObject call(Map[span class="typ">String, Object
if (args.length != 2) {
throw new IllegalArgumentException("Add only supports two arguments");
}
Number left = FunctionUtils.getNumberValue(0, args, env);
Number right = FunctionUtils.getNumberValue(1, args, env);
return new AviatorDouble(left.doubleValue() + right.doubleValue());
}
public String getName() {
return "add";
}
}
注册到AviatorEvaluator并调用如下:
//注册函数
AviatorEvaluator.addFunction(new AddFunction());
System.out.println(AviatorEvaluator.execute("add(1,2)"));
System.out.println(AviatorEvaluator.execute("add(add(1,2),100)"));
注册函数通过AviatorEvaluator.addFunction方法,移除可以通过removeFunction。
编译表达式?
上面提到的例子都是直接执行表达式,事实上Aviator背后都帮你做了编译并执行的工作。你可以自己先编译表达式,返回一个编译的结果,然后传入不同的env来复用编译结果,提高性能,这是更推荐的使用方式:
import java.util.HashMap;
import java.util.Map;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
public class CompileExample {
public static void main(String【】 args) {
String expression = "a-(b-c)>100";
// 编译表达式
Expression compiledExp = AviatorEvaluator.compile(expression);
Map[span class="typ">String, ObjectString, Object
env.put("a", 100.3);
env.put("b", 45);
env.put("c", -199.100);
// 执行表达式
Boolean result = (Boolean) compiledExp.execute(env);
System.out.println(result);
}
}
通过compile方法可以将表达式编译成Expression的中间对象,当要执行表达式的时候传入env并调用Expression的execute方法即可。表达式中使用了括号来强制优先级,这个例子还使用了>用于比较数值大小,比较运算符!=、==、>、>=、<、<=不仅可以用于数值,也可以用于String、Pattern、Boolean等等,甚至是任何用户传入的两个都实现了java.lang。Comparable接口的对象之间。
编译后的结果你可以自己缓存,也可以交给Aviator帮你缓存,AviatorEvaluator内部有一个全局的缓存池,如果你决定缓存编译结果,可以通过:
public static Expression compile(String expression, boolean cached)
将cached设置为true即可,那么下次编译同一个表达式的时候将直接返回上一次编译的结果。使缓存失效通过:
public static void invalidateCache(String expression)
方法。
访问数组和集合?
可以通过中括号去访问数组和java.util.List对象,可以通过map.key访问java.util.Map中key对应的value,一个例子:
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.googlecode.aviator.AviatorEvaluator;
public class CollectionExample {
public static void main(String【】 args) {
final List[span class="typ">StringString
list.add("hello");
list.add(" world");
final int【】 array = new int【3】;
array【0】 = 0;
array【1】 = 1;
array【2】 = 3;
final Map[span class="typ">String, DateString, Date
map.put("date", new Date());
&