一、轮子的必要性
表达式的求值上,java的选择非常多,强大的如Groovy、JRuby,N年没维护的beanshell,包括javaeye上朋友的IKExpression。为什么还需要Aviator?或者说Aviator的特点是什么?
我将Aviator定位在Groovy这样全功能的脚本和IKExpression这样的简易的表达式求值之间的东西,如果你不希望带上Groovy那么庞大的jar却只用上一点点的功能,如果你希望功能和性能上比IKExpression好那么一些,那么也许你可以考虑Aviator。
Aviator的设计思路跟利用GroovyObject的求值是一样,通过编译并动态生成字节码的方式将表达式编译成一个类,然后反射执行这个类,因此会在效率上比纯解释执行的IKExpression好一些。
二、让轮子转起来。
求算术表达式:
- 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);
- }
- }
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); } }
执行入口统一为AviatorEvaluator类,它有一系列静态方法。
逻辑表达式和关系运算:
- AviatorEvaluator.execute("3>1 && 2!=4 || true");
AviatorEvaluator.execute("3>1 && 2!=4 || true");
Aviator支持所有的关系运算符和算术运算符,不支持位运算,同时支持表达式的优先级,优先级跟Java的运算符一样,并且支持通过括号来强制优先级。
使用变量和字符串相加:
- String yourname = “aviator”;
- Map<String, Object> env = new HashMap<String, Object>();
- env.put("yourname", yourname);
- String result = (String) AviatorEvaluator.execute(" 'hello ' + yourname ", env);
- System.out.println(result);
String yourname = “aviator”; Map<String, Object> env = new HashMap<String, Object>(); env.put("yourname", yourname); String result = (String) AviatorEvaluator.execute(" 'hello ' + yourname ", env); System.out.println(result);
打印:
- hello aviator
hello aviator
字符串可以单引号也可以双引号括起来,并且支持转义字符。变量名称只要是合法的java identifer即可,变量需要用户传入,通过Map<String,Object>指定变量名和值是什么,这里的变量是yourname。
变量的访问支持嵌套访问,也就是dot操作符来访问变量里的属性,假设我们有一个Foo类:
- public static class Foo {
- int i;
- float f;
- Date date = new Date();
- public Foo(int i, float f, Date date) {
- super();
- this.i = i;
- this.f = f;
- this.date = date;
- }
- public int getI() {
- return i;
- }
- public void setI(int i) {
- this.i = i;
- }
- public float getF() {
- return f;
- }
- public void setF(float f) {
- this.f = f;
- }
- public Date getDate() {
- return date;
- }
- public void setDate(Date date) {
- this.date = date;
- }
- }
public static class Foo { int i; float f; Date date = new Date(); public Foo(int i, float f, Date date) { super(); this.i = i; this.f = f; this.date = date; } public int getI() { return i; } public void setI(int i) { this.i = i; } public float getF() { return f; } public void setF(float f) { this.f = f; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
然后在使用一个表达式来描述Foo里的各种属性:
- Foo foo = new Foo(100, 3.14f, new Date());
- Map<String, Object> env = new HashMap<String, Object>();
- env.put("foo", foo);
- String result =
- (String) AviatorEvaluator.execute(
- " '[foo i='+ foo.i + ' f='+foo.f+' year='+(foo.date.year+1900)+ ' month='+foo.date.month +']' ",
- env);
Foo foo = new Foo(100, 3.14f, new Date()); Map<String, Object> env = new HashMap<String, Object>(); env.put("foo", foo); String result = (String) AviatorEvaluator.execute( " '[foo i='+ foo.i + ' f='+foo.f+' year='+(foo.date.year+1900)+ ' month='+foo.date.month +']' ", env);
我们可以通过foo.date.year的方式来访问变量foo中date属性的year值,这是利用commons-beanutils的反射功能实现的,前提是你的变量是合法的JavaBean(public、getter缺一不可)。
三元表达式:
- AviatorEvaluator.execute("3>0? 'yes':'no'");
AviatorEvaluator.execute("3>0? 'yes':'no'");
上面都还是一个求值器表达式的常见功能,下面要描述的是Aviator的一些偏脚本性的功能。
类Ruby、Perl的正则匹配,匹配email地址:
- AviatorEvaluator.execute("'killme2008'=~/([\\w0-8]+@\\w+[\\.\\w+]+)/ ");
AviatorEvaluator.execute("'killme2008'=~/([\\w0-8]+@\\w+[\\.\\w+]+)/ ");
成功的话返回true,否则返回false。//括起来的字符序列成为正则表达式,=~操作符用于匹配。匹配只能在String和Pattern之间。
匹配成功,获得匹配的分组,利用变量$digit:
- AviatorEvaluator.execute("'killme2008@gmail.com'=~/([\\w0-8]+@\\w+[\\.\\w+]+)/ ? $1:'unknow'");
AviatorEvaluator.execute("'killme2008@gmail.com'=~/([\\w0-8]+@\\w+[\\.\\w+]+)/ ? $1:'unknow'");
匹配成功返回$1,表示第一个匹配的分组,也就是用户名 killme2008
函数调用:
- AviatorEvaluator.execute("sysdate()");
AviatorEvaluator.execute("sysdate()");
sysdate()是一个内置函数,返回当前日期,跟new java.util.Date()效果相同。
更多内置函数:
- AviatorEvaluator.execute("string.length('hello')"); // 求字符串长度
- AviatorEvaluator.execute("string.contains('hello','h')"); //判断字符串是否包含字符串
- AviatorEvaluator.execute("string.startsWith('hello','h')"); //是否以子串开头
- AviatorEvaluator.execute("string.endsWith('hello','llo')"); 是否以子串结尾
- AviatorEvaluator.execute("math.pow(-3,2)"); // 求n次方
- AviatorEvaluator.execute("math.sqrt(14.0)"); //开平方根
- AviatorEvaluator.execute("math.sin(20)"); //正弦函数
AviatorEvaluator.execute("string.length('hello')"); // 求字符串长度 AviatorEvaluator.execute("string.contains('hello','h')"); //判断字符串是否包含字符串 AviatorEvaluator.execute("string.startsWith('hello','h')"); //是否以子串开头 AviatorEvaluator.execute("string.endsWith('hello','llo')"); 是否以子串结尾 AviatorEvaluator.execute("math.pow(-3,2)"); // 求n次方 AviatorEvaluator.execute("math.sqrt(14.0)"); //开平方根 AviatorEvaluator.execute("math.sin(20)"); //正弦函数
可以看到Aviator的函数调用风格非常类似lua或者c。
自定义函数,实现AviatorFunction接口并注册即可,比如我们实现一个add函数用于相加:
- import com.googlecode.aviator.AviatorEvaluator;
- 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;
- class AddFunction implements AviatorFunction {
- public AviatorObject call(Map<String, Object> env, AviatorObject... args) {
- 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";
- }
- }
import com.googlecode.aviator.AviatorEvaluator; 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; class AddFunction implements AviatorFunction { public AviatorObject call(Map<String, Object> env, AviatorObject... args) { 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.addFunction(new AddFunction());
- System.out.println(AviatorEvaluator.execute("add(1,2)"));
- System.out.println(AviatorEvaluator.execute("add(add(1,2),100)"));
AviatorEvaluator.addFunction(new AddFunction()); System.out.println(AviatorEvaluator.execute("add(1,2)")); System.out.println(AviatorEvaluator.execute("add(add(1,2),100)"));
函数可以嵌套调用。
三、不公平的性能测试
基本介绍完了,最后给些测试的数据,下列的测试场景都是每个表达式预先编译,然后执行1000万次,测量执行耗时。
场景1:
算术表达式
1000+100.0*99-(600-3*15)/(((68-9)-3)*2-100)+10000%7*71
结果:
测试 | 耗时(单位:秒) |
Aviator | 14.0 |
Groovy | 79.6 |
IKExpression | 159.2 |
场景2:
计算逻辑表达式和三元表达式混合:
6.7-100>39.6?5==5?4+5:6-1:!(100%3-39.0<27)?8*2-199:100%3
测试结果:
测试 | 耗时(单位:秒) |
Aviator | 11.0 |
Groovy | 13.0 |
IKExpression | 168.8 |
场景3:
计算算术表达式和逻辑表达式的混合,带有5个变量的表达式:
i * pi +(d * b -199)/(1- d * pi)-(2+100- i / pi)%99==i * pi +(d * b -199)/(1- d * pi)-(2+100- i / pi)%99
变量设定为:
int i =100; float pi =3.14f; double d =-3.9; byte b =(byte)4; booleanbool=false;
每次执行前都重新设置这些变量的值。
结果:
测试 | 耗时(单位:秒) |
Aviator | 31.2 |
Groovy | 9.7 |
IKExpression | 编译错误 |
场景4:
- Aviator执行 sysdate()
- groovy执行 new java.util.Date()
- IKExpression执行 $SYSDATE()
结果:
测试 | 耗时(单位:秒) |
Aviator | 22.6 |
Groovy | 13.9 |
IKExpression | 25.4 |
原始的测试报告在这里。
四、结语
能看到这里,并且感兴趣的朋友请点击项目主页:
http://code.google.com/p/aviator/
下载地址:
http://code.google.com/p/aviator/downloads/list
完整的用户手册:
http://code.google.com/p/aviator/wiki/User_Guide_zh
目前版本仍然是1.0.0-RC,希望更多朋友试用并最终release。有什么疑问或者建议请跟贴。
相关推荐
《Aviator:高性能Java表达式求值程序的深入解析》 Aviator,作为一个轻量级且高效的Java表达式执行引擎,其设计目标是为开发者提供一种动态编译和执行表达式的能力,使得在运行时能够灵活处理各种计算逻辑。这个...
Aviator的实现思路与其他轻量级的求值器不同,其他求值器通常是通过解释的方式运行,而Aviator则是直接将表达式编译成Java字节码,然后交由JVM执行,这样可以提供优秀的性能。 Aviator支持大部分运算操作符,包括...
Aviator——轻量级Java表达式求值引擎,这个是下载下来的jar包,版本是4.1.2
Aviator是一个强大的Java库,专为高效且轻量级的表达式求值设计。它作为一个表达式解析器和引擎,允许在运行时动态地评估各种复杂的逻辑和计算表达式。这个压缩包包含了从Aviator 2.1版本到3.11版本的jar包,覆盖了...
Aviator是一个高性能、轻量级的基于java实现的表达式引擎,它动态地将String类型的表达式编译成Java ByteCode并交给JVM执行。 Aviator支持所有的关系运算符和算术运算符,不支持位运算,同时支持表达式的优先级,...
尽管市面上已经存在多种用于动态求值的Java表达式引擎,但Aviator以其独特的设计目标——轻量级和高性能——脱颖而出。相较于Groovy或JRuby等更为复杂的脚本语言,Aviator的体积更小(加上所有依赖包仅450KB,若不计...
Aviator是一款开源的轻量级、高性能的表达式求值引擎,主要应用于Java环境中。它设计的目的是为了方便地在程序运行时动态执行复杂的逻辑表达式,为开发者提供了灵活的数据处理能力。Aviator 2.3.0是该库的一个稳定...
Aviator是一个为Java设计的高效且轻量级的表达式求值引擎,它的主要功能是解析并执行动态的字符串表达式,为应用程序提供灵活的数据处理能力。在Java开发中,尤其是在需要动态计算或者业务规则频繁变化的场景下,...
这是一款由Google开发的开源项目,主要功能是实现动态的、高性能的表达式计算。Aviator的设计理念是提供一个强大的计算引擎,使得开发者可以在运行时动态构建和执行表达式,极大地提升了开发效率。 Aviator的核心...
Aviator 是一个强大的 Java 表达式执行引擎,它允许你在运行时动态计算表达式,类似于 JavaScript 或者其他脚本语言。在Java应用中,Aviator 特别适合用于数据分析和处理,例如对 List 中的数据进行求和、排序、找出...
作为一个轻量级的规则引擎,Aviator 提供了一种简洁而强大的方式来处理动态计算和决策过程。本文将深入探讨 Aviator 的核心概念、功能特性以及如何在实际项目中应用。 ### 1. Aviator 的核心概念 #### 1.1 表达式 ...
赠送jar包:aviator-5.2.6.jar; 赠送原API文档:aviator-5.2.6-javadoc.jar; 赠送源代码:aviator-5.2.6-sources.jar; 赠送Maven依赖信息文件:aviator-5.2.6.pom; 包含翻译后的API文档:aviator-5.2.6-javadoc-...
Fel(Fast Expression Language)是开放的、高效的、轻量级的表达式语言。拥有解释执行和编译执行双引擎。Fel在编译执行时,做了很多优化,适合处理海量数据。Fel扩展性强,用户可以定制Fel执行时的众多环节,以满足...
赠送jar包:aviator-5.1.4.jar; 赠送原API文档:aviator-5.1.4-javadoc.jar; 赠送源代码:aviator-5.1.4-sources.jar; 赠送Maven依赖信息文件:aviator-5.1.4.pom; 包含翻译后的API文档:aviator-5.1.4-javadoc-...
赠送jar包:aviator-5.2.6.jar; 赠送原API文档:aviator-5.2.6-javadoc.jar; 赠送源代码:aviator-5.2.6-sources.jar; 赠送Maven依赖信息文件:aviator-5.2.6.pom; 包含翻译后的API文档:aviator-5.2.6-javadoc-...
赠送jar包:aviator-5.1.4.jar; 赠送原API文档:aviator-5.1.4-javadoc.jar; 赠送源代码:aviator-5.1.4-sources.jar; 赠送Maven依赖信息文件:aviator-5.1.4.pom; 包含翻译后的API文档:aviator-5.1.4-javadoc-...
Easy Rules,Drools,Aviator表达式求值引擎,Rule Book、Oracle Rules SDK、Blaze (fico)、IBM Decision Manager,DTRules,DSL规则引擎 规则引擎由三部分 事实(Fact):已知对象,比如以上刷卡的行为,即成事实...
set ScriptEngineFactory.getLanguageName return aviator by @qiukeren in #525 Improve class cache performance when class not found by @jiudc in #522 fix: capitalize java bean property names by @killme...
在计算机科学中,表达式是能够产生一个值的语句,它可以是简单的常量、变量,也可以是复杂的运算结构,如加减乘除、函数调用等。例如,"2 + 3"就是一个简单的算术表达式,它的结果是5。 表达式解析的过程通常分为两...
主要是Google放开的java源码,针对java的自定义的表达式实现,比如说实现¥¥¥&&&||||与逻辑或的实现源码,1、进行表达式解析,获取里面的单引号参数,然后解析成表达式入参,2、逻辑运算的加减乘除的实现逻辑,...