程序与技术分享:Aviator表达式求值引擎开源框架

简介: 程序与技术分享:Aviator表达式求值引擎开源框架

简介?


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());


&

相关文章
|
2月前
|
缓存 安全 Java
|
2月前
|
C++
关系表达式:编程中的比较利器
在编程中,关系表达式扮演着至关重要的角色。它们允许我们比较两个或多个值,并基于这些比较的结果来执行相应的操作。关系表达式通过返回布尔值(真或假)来告诉我们两个值之间的关系,从而帮助我们在程序中做出决策。
26 0
|
2月前
|
Python
Python语言的表达式
Python语言的表达式
|
2月前
|
机器学习/深度学习 开发框架 .NET
C# 中的 Lambda 表达式:一种简洁而强大的编程工具
【1月更文挑战第6天】在现代编程中,Lambda 表达式已经成为一种非常流行的编程范式。C# 作为一种功能强大的、面向对象的编程语言,自然也不例外。Lambda 表达式在 C# 中提供了一种简洁、灵活的方式来表示匿名函数。这些函数可以被用作委托或表达式树类型,从而在各种不同的上下文中使用。
|
2月前
|
JavaScript
连等表达式的核心原理
连等表达式的核心原理
|
10月前
|
存储 SQL 分布式计算
Velox表达式计算原理调研
velox是Meta开源的高性能的C++计算引擎,本文主要来调研下其表达式计算的实现原理。
501 3
|
存储 自然语言处理 算法
GaiaX开源解读 | 表达式作为逻辑动态化的基础,我们是如何设计的
GaiaX跨端模板引擎,是在阿里优酷、淘票票、大麦内广泛使用的Native动态化方案,其核心优势是性能、稳定和易用。本系列文章《GaiaX开源解读》,带大家看看过去三年GaiaX的发展过程。
289 0
|
缓存 监控 算法
Google Aviator——轻量级 Java 表达式引擎实战
Drools(JBoss Rules )是一个开源业务规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。
912 0
Google Aviator——轻量级 Java 表达式引擎实战
|
存储 自然语言处理 算法
作为逻辑动态化的基础,GaiaX 表达式是如何设计的? | GaiaX 开源解读
GaiaX 跨端模板引擎,是在阿里文娱内广泛使用的 Native 动态化方案,其核心优势是性能、稳定和易用。本系列文章《GaiaX 开源解读》,带大家看看过去三年 GaiaX 的发展过程。 GaiaX 开源地址:https://github.com/alibaba/GaiaX
347 0
作为逻辑动态化的基础,GaiaX 表达式是如何设计的? | GaiaX 开源解读
|
数据采集 安全 Go
Python网络爬虫简介与表达式基础|学习笔记
快速学习Python网络爬虫简介与表达式基础
109 0