Aviator简介
Aviator是一个高性能、轻量级的 java 语言实现的表达式求值引擎, 主要用于各种表达式的动态求值。现在已经有很多开源可用的 java 表达式求值引擎,为什么还需要 Avaitor 呢?
Aviator的设计目标是轻量级和高性能,相比于Groovy、JRuby的笨重, Aviator非常小, 加上依赖包也才 537K,不算依赖包的话只有 70K; 当然, Aviator的语法是受限的, 它不是一门完整的语言, 而只是语言的一小部分集合。
其次, Aviator的实现思路与其他轻量级的求值器很不相同, 其他求值器一般都是通过解释的方式运行, 而Aviator则是直接将表达式编译成 JVM 字节码, 交给 JVM 去执行。简单来说, Aviator的定位是介于 Groovy 这样的重量级脚本语言和 IKExpression 这样的轻量级表达式引擎之间。
AviatorScript 是一门高性能、轻量级寄宿于 JVM (包括 Android 平台)之上的脚本语言。
Aviator 使用场景
- 常见的公式计算
- 数据处理转换
- 数据核对
- 工作流逻辑判定
- 鉴权校验等等
- 动态脚本控制
- 规则判断及规则引擎
Aviator 的特性:
- 支持数字、字符串、正则表达式、布尔值、正则表达式等基本类型,完整支持所有 Java 运算符及优先级等。
- 函数是一等公民,支持闭包和函数式编程。
- 内置 bigint/decmal 类型用于大整数和高精度运算,支持运算符重载得以让这些类型使用普通的算术运算符 +-*/ 参与运算。
- 完整的脚本语法支持,包括多行数据、条件语句、循环语句、词法作用域和异常处理等。
- 函数式编程结合 Sequence 抽象,便捷处理任何集合。
- 轻量化的模块系统。
- 多种方式,方便地调用 Java 方法,完整支持 Java 脚本 API(方便从 Java 调用脚本)。
- 丰富的定制选项,可作为安全的语言沙箱和全功能语言使用。
- 轻量化,高性能,ASM 模式下通过直接将脚本翻译成 JVM 字节码,解释模式可运行于 Android 等非标 Java 平台
- 语法糖支持a.b.c.d
- 支持script执行
Aviator的设计是通过编译并动态生成字节码的方式将表达式编译成一个类,然后反射执行这个类
AviatorScript 文档: AviatorScript 文档 · 语雀
源码:GitHub - killme2008/aviatorscript: A high performance scripting language hosted on the JVM.
快速开始
推荐使用版本 5.2.6 及以上
1、POM.XML中引入AVIATOR依赖
<dependency><groupId>com.googlecode.aviator</groupId><artifactId>aviator</artifactId><version>5.2.6</version></dependency>
2、基本使用
public static void main(String[] args) {System.out.println("-----------------------------------------------------------------");System.out.println("算术表达式【1+1】: " + AviatorEvaluator.execute("1+1"));System.out.println("逻辑表达式【1==1】: " + AviatorEvaluator.execute("1==1"));System.out.println("三元表达式【1==1 ? '对' : '错'】: " + AviatorEvaluator.execute("1==1 ? '对' : '错'"));System.out.println("正则表达式: " + AviatorEvaluator.execute("'killme@2008gmail.com'=~/([\\w0-8]+@\\w+[\\.\\w+]+)/ ? $1:'unknow'"));System.out.println("-----------------------------------------------------------------");System.out.println("函数调用【6的3次方】: " + AviatorEvaluator.execute("math.pow(6,3)"));System.out.println("求字符串长度: " + AviatorEvaluator.execute("string.length('hello')"));System.out.println("判断字符串是否包含字符串: " + AviatorEvaluator.execute("string.contains('hello','h')"));System.out.println("是否以子串开头: " + AviatorEvaluator.execute("math.pow(-3,2)"));System.out.println("求n次方: " + AviatorEvaluator.execute("math.sqrt(14.0)"));System.out.println("正弦函数: " + AviatorEvaluator.execute("math.sin(20)"));System.out.println("-----------------------------------------------------------------");Map env = new HashMap(16);env.put("yourname","aviator");String result3 = (String)AviatorEvaluator.execute(" 'hello ' + yourname ", env);System.out.println("变量和字符串相加:"+ result3);System.out.println("-----------------------------------------------------------------");}
执行结果
-----------------------------------------------------------------
算术表达式【1+1】: 2
逻辑表达式【1==1】: true
三元表达式【1==1 ? '对' : '错'】: 对
正则表达式: killme@2008gmail.com
-----------------------------------------------------------------
函数调用【6的3次方】: 216.0
求字符串长度: 5
判断字符串是否包含字符串: true
是否以子串开头: 9.0
求n次方: 3.7416573867739413
正弦函数: 0.9129452507276277
-----------------------------------------------------------------
变量和字符串相加:hello aviator
-----------------------------------------------------------------
语法介绍
1、系统函数
函数名称 | 说明 |
assert(predicate, [msg]) | 断言函数,当 predicate 的结果为 false 的时候抛出 AssertFailed 异常, msg 错误信息可选。 |
sysdate() | 返回当前日期对象 java.util.Date |
rand() | 返回一个介于 [0, 1) 的随机数,结果为 double 类型 |
rand(n) | 返回一个介于 [0, n) 的随机数,结果为 long 类型 |
cmp(x, y) | 比较 x 和 y 大小,返回整数,0 表示相等, 1 表达式 x > y,负数则 x < y。 |
print([out],obj) | 打印对象,如果指定 out 输出流,向 out 打印, 默认输出到标准输出 |
println([out],obj) 或者 p([out], obj) | 与 print 类似,但是在输出后换行 |
pst([out], e); | 等价于 e.printStackTrace(),打印异常堆栈,out 是可选的输出流,默认是标准错误输出 |
now() | 返回 System.currentTimeMillis() 调用值 |
long(v) | 将值转为 long 类型 |
double(v) | 将值转为 double 类型 |
boolean(v) | 将值的类型转为 boolean,除了 nil 和 false,其他都值都将转为布尔值 true。 |
str(v) | 将值转为 string 类型,如果是 nil(或者 java null),会转成字符串 'null' |
bigint(x) | 将值转为 bigint 类型 |
decimal(x) | 将值转为 decimal 类型 |
identity(v) | 返回参数 v 自身,用于跟 seq 库的高阶函数配合使用。 |
type(x) | 返回参数 x 的类型,结果为字符串,如 string, long, double, bigint, decimal, function 等。Java 类则返回完整类名。 |
is_a(x, class) | 当 x 是类 class 的一个实例的时候,返回 true,例如 |
is_def(x) | 返回变量 x 是否已定义(包括定义为 nil),结果为布尔值 |
undef(x) | “遗忘”变量 x,如果变量 x 已经定义,将取消定义。 |
range(start, end, [step]) | 创建一个范围,start 到 end 之间的整数范围,不包括 end, step 指定递增或者递减步幅。 |
tuple(x1, x2, ...) | 创建一个 Object 数组,元素即为传入的参数列表。 |
eval(script, [bindings], [cached]) | 对一段脚本文本 script 进行求值,等价于 AviatorEvaluator.execute(script, env, cached) |
comparator(pred) | 将一个谓词(返回布尔值)转化为 java.util.Comparator 对象,通常用于 sort 函数。 |
max(x1, x2, x3, ...) | 取所有参数中的最大值,比较规则遵循逻辑运算符规则。 |
min(x1, x2, x3, ...) | 取所有参数中的最小值,比较规则遵循逻辑运算符规则。 |
constantly(x) | 用于生成一个函数,它对任意(个数)参数的调用结果 x。 |
2、字符串函数
date_to_string(date,format) | 将 Date 对象转化化特定格式的字符串,2.1.1 新增 |
string_to_date(source,format) | 将特定格式的字符串转化为 Date 对 象,2.1.1 新增 |
string.contains(s1,s2) | 判断 s1 是否包含 s2,返回 Boolean |
string.length(s) | 求字符串长度,返回 Long |
string.startsWith(s1,s2) | s1 是否以 s2 开始,返回 Boolean |
string.endsWith(s1,s2) | s1 是否以 s2 结尾,返回 Boolean |
string.substring(s,begin[,end]) | 截取字符串 s,从 begin 到 end,如果忽略 end 的话,将从 begin 到结尾,与 java.util.String.substring 一样。 |
string.indexOf(s1,s2) | java 中的 s1.indexOf(s2),求 s2 在 s1 中 的起始索引位置,如果不存在为-1 |
string.split(target,regex,[limit]) | Java 里的 String.split 方法一致,2.1.1 新增函数 |
string.join(seq,seperator) | 将集合 seq 里的元素以 seperator 为间隔 连接起来形成字符串,2.1.1 新增函数 |
string.replace_first(s,regex,replacement) | Java 里的 String.replaceFirst 方法, 2.1.1 新增 |
string.replace_all(s,regex,replacement) | Java 里的 String.replaceAll 方法 , 2.1.1 新增 |
3、数学函数
math.abs(d) | 求 d 的绝对值 |
math.round(d) | 四舍五入 |
math.floor(d) | 向下取整 |
math.ceil(d) | 向上取整 |
math.sqrt(d) | 求 d 的平方根 |
math.pow(d1,d2) | 求 d1 的 d2 次方 |
math.log(d) | 求 d 的自然对数 |
math.log10(d) | 求 d 以 10 为底的对数 |
math.sin(d) | 正弦函数 |
math.cos(d) | 余弦函数 |
math.tan(d) | 正切函数 |
math.atan(d) | 反正切函数 |
math.acos(d) | 反余弦函数 |
math.asin(d) | 反正弦函数 |
4、语法糖
public class TestAviator1 {public static void main(String[] args) {Foo foo = new Foo(100, 3.14f, new Date());Map<String, Object> env = new HashMap<>();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);System.out.println("执行结果:"+result);}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 float getF() {return f;}public Date getDate() {return date;}}
}
执行结果
[foo i=100 f=3.14 year=2022 month=3]
集合处理
List<Map<String,Object>> list1=new ArrayList<>();
Map<String,Object> map1=new HashMap<>();
map1.put("name","我看那水");
map1.put("address","傻吊奥迪阿萨斯短时");
list1.add(map1);
map1=new HashMap<>();
map1.put("name","奥斯卡");
map1.put("address","地方进去恢复期计划和");
list1.add(map1);List<Map<String,Object>> list=new ArrayList<>();Map<String,Object> map=new HashMap<>();
map.put("coco",list1);
map.put("flag","收到货后");
list.add(map);
map=new HashMap<>();
map.put("coco",list1);
map.put("flag","爱莎");
list.add(map);Map<String,Object> env=new HashMap<>();
env.put("data",list);System.out.println( AviatorEvaluator.execute("#data.[1].flag", env, true));System.out.println( AviatorEvaluator.execute("#data.[0].coco.[0].name", env, true));
执行结果
爱莎
我看那水
5、自定义函数
/*** 判断函数** @author carson deng* @data 2021/08/06*/
public class IfFunction extends AbstractFunction {/*** IF(bool,A,B)** @param env 数据源* @param arg1 条件值* @param arg2 值1* @param arg3 值2* @return*/@Overridepublic AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {Boolean flag = FunctionUtils.getBooleanValue(arg1, env);return AviatorRuntimeJavaType.valueOf(flag ? arg2.getValue(env) : arg3.getValue(env));}/*** IF(bool,rule,A,B)** @param env 数据源* @param arg1 条件值* @param arg2 KEY对应关系数据 target* @param arg3 规则对象1 MAP 对象* @param arg4 规则对象2 MAP 对象* @return*/@Overridepublic AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4) {Boolean flag = FunctionUtils.getBooleanValue(arg1, env);Map<String, Object> target = (Map<String, Object>) FunctionUtils.getJavaObject(arg2, env);Map<String, Object> rule;if (flag) {rule = (Map<String, Object>) FunctionUtils.getJavaObject(arg3, env);} else {rule = (Map<String, Object>) FunctionUtils.getJavaObject(arg4, env);}Map<String, Object> result = new HashMap<>(target.size());for (String key : rule.keySet()) {result.put(key, target.get(rule.get(key)));}return AviatorRuntimeJavaType.valueOf(result);}/*** 函数名称** @return*/@Overridepublic String getName() {return "fpx.if";}
}
使用自定义函数
//自定义函数执行AviatorEvaluator.addFunction(new IFFunction());Map env1 = new HashMap(16);env.put("yourname","aviator");String result4 = (String)AviatorEvaluator.execute("IF(yourname=='aviator','我是aviator','我不是aviator')", env);System.out.println("自定义函数:"+ result4);
执行结果
自定义函数:我是aviator
6、调用 Java 类方法和 Function Missing
默认情况下, aviator 能调用的函数列表是受限的,这是基于安全和控制的角度考虑,不允许表达式调用任意方法。
如果你想调用某个对象的 java 方法,aviator 提供了下列两种方式:
- 自定义函数包装下,比较推荐的方式,可以避免反射。
- 导入方法作为自定义函数,基于反射的方式自动导入和调用,性能相对较差一些(JDK 8 上大概有 3 倍左右的差距)
private static class TestFunctionMissing implements FunctionMissing {@Overridepublic AviatorObject onFunctionMissing(final String name, final Map<String, Object> env,final AviatorObject... args) {// 当实现并设置了该处理器后,没有找到的函数调用都将调用该处理器执行System.out.println("Function not found, name=" + name + ", env=" + env + ", args=" + Arrays.toString(args));return FunctionUtils.wrapReturn(name);}}public static void main(final String[] args) {// Set function missing handler.AviatorEvaluator.setFunctionMissing(new TestFunctionMissing());System.out.println(AviatorEvaluator.execute("test(1,2,3)"));System.out.println(AviatorEvaluator.execute("not_found(1,2,3)"));}
- 性能相比自定义函数较差,接近 3 倍的差距,原因也是反射。
- 无法调用静态方法,静态方法调用仍然需要采用其他两种方式。
- 如果第一个参数为 null,无法找出方法,因为没有对象 class 信息。
函数加载java静态方法
//调用java静态方法
AviatorEvaluator.addStaticFunctions("str", StringUtils.class);
System.out.println(AviatorEvaluator.execute("str.isNotBlank('hello')"));
//调用java方法
AviatorEvaluator.addInstanceFunctions("s", String.class);
System.out.println(AviatorEvaluator.execute("s.indexOf('hello','l')"));
7、调用脚本函数
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;public class InvokeScriptFunction {public static void main(final String[] args) throws Exception {ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("AviatorScript");// AviatorScript code in a StringString script = "fn hello(name) { print('Hello, ' + name); }";// evaluate scriptengine.eval(script);// javax.script.Invocable is an optional interface.// Check whether your script engine implements or not!// Note that the AviatorScript engine implements Invocable interface.Invocable inv = (Invocable) engine;// invoke the global function named "hello"inv.invokeFunction("hello", "Scripting!!" );}
}
5、SpringBoot 整合 相关配置介绍
最佳实践:最佳实践 · 语雀
/*** 初始化表达式** @author carson deng* @data 2021/08/17*/
@Configuration
public class FunctionConfig {@PostConstructpublic void init() {// AviatorEvaluator.EVAL,默认值,以运行时的性能优先,编译会花费更多时间做优化,目前会做一些常量折叠、公共变量提取的优化。适合长期运行的表达式。 表达式经常不会变化。
// AviatorEvaluator.COMPILE 不会做任何编译优化,牺牲一定的运行性能,适合需要频繁编译表达式的场景, 比如经常编译不同的表达式。//执行优先AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.EVAL);//编译优先 你可以修改为编译速度优先,这样不会做编译优化://AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.COMPILE);//打开跟踪执行 默认关闭AviatorEvaluator.setOption(Options.TRACE_EVAL, true);//启用属性访问语法时,如果未找到属性值或引发异常,返回NULL 默认值为false 设置为trueAviatorEvaluator.setOption(Options.NIL_WHEN_PROPERTY_NOT_FOUND, true);//计算精度 java.util.MathContext.DECIMAL128AviatorEvaluator.setOption(Options.MATH_CONTEXT, MathContext.DECIMAL128);//浮点数解析//是否将整型数字都解析为 BigDecimal,默认为 false,也就是不启用。在所有数字都是需要高精度计算的场景,结合 ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL 选项,可以减少一些类型转换。AviatorEvaluator.setOption(Options.ALWAYS_PARSE_INTEGRAL_NUMBER_INTO_DECIMAL, false);//解析浮点数 默认 false//是否将所有浮点数解析为 Decimal 类型,适合需要高精度运算的场景,并且不想为每个浮点数字指定 M 后缀(表示 Decimal 类型)。默认为 false 不开启。AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, false);/*** 正则分组捕获 默认为 true 开启* email=~/([\\w0-8]+)@\\w+[\\.\\w+]+/ ? $1:'unknow'* 将 email 变量中的用户名部分(@ 符号之前)匹配出来,并放到 $1变量中,如果关闭 PUT_CAPTURING_GROUPS_INTO_ENV(设置为 false),将不会将捕获的分组放入 env,也就无法获取到匹配的分组。默认为 true 开启。*/AviatorEvaluator.setOption(Options.PUT_CAPTURING_GROUPS_INTO_ENV, true);/*** 变量语法糖* 是否启用变量访问的语法糖,默认情况下 Aviator 会通过 commons-beantuils 反射访问类似 a.b.c 这样的嵌套 JavaBean 变量,或者 #list.[0].name 这样的数组(链表)中的元素。但是部分用户可能想关闭这个行为,强制都从 env 中获取这些变量值,那么就可以将该选项关闭,也就是设置为 false。默认为 true 开启。*/AviatorEvaluator.setOption(Options.ENABLE_PROPERTY_SYNTAX_SUGAR, true);/*** Env 处理* 从 4.0 开始,为了支持 lambda, aviator 引入了变量作用域 scope 的概念,本来的默认行为是不再修改用户传入的 env 对象,但是后面看到比较多的用户依赖这个行为,因此提供了这个新选项 USE_USER_ENV_AS_TOP_ENV_DIRECTLY,当为 true 的时候就会将用户传入的 env 作为最顶层的作用域 scope 来使用,并且默认为 true 启用。如果你不需要 aviator 产生副作用污染你传入的 env,这个选项更推荐设置为 false*/AviatorEvaluator.setOption(Options.USE_USER_ENV_AS_TOP_ENV_DIRECTLY, true);/*** 参数捕获 默认false*/AviatorEvaluator.setOption(Options.CAPTURE_FUNCTION_ARGS, false);/*** 循环次数控制* 限制循环语句的最大次数,这个循环包括 for 语句、 while 循环语句以及 map, filter, some 等任何涉及 sequence 遍历的高阶函数。用于限制用户传入的脚本执行循环的次数,避免死循环或者耗费大量 CPU 的场景出现。** 默认值: 0,表示无限制。* 可以设置为任意正整数,比如 5000,表示单次循环最大次数是 5000。*/AviatorEvaluator.setOption(Options.MAX_LOOP_COUNT, 0);/*** 语法特性 设置 AviatorScript 支持的语法特性集合,它接受的是一个 Set<Feature> 的集合*/AviatorEvaluator.setOption(Options.FEATURE_SET, Feature.asSet(Feature.Assignment,Feature.ForLoop,Feature.WhileLoop,Feature.Lambda,Feature.Let));/*** 类的白名单:ALLOWED_CLASS_SET* 请注意:* ● null 表示不限制(默认值)* ● 空集合表示禁止任何 class*/AviatorEvaluator.setOption(Options.ALLOWED_CLASS_SET, (new HashSet<Object>()).add(ArrayBlockingQueue.class));//设置默认缓存表达式结果AviatorEvaluator.getInstance().setCachedExpressionByDefault(true);//设置LRU缓存AviatorEvaluator.getInstance().useLRUExpressionCache(20000);}
}
参数捕获:CAPTURE_FUNCTION_ARGS
是否捕获函数调用点的参数列表,如果启用,那么类似 func
这样的自定义函数:
func(a, b, c, 100+2)
这样的表达式,就可以在 func 内得到调用的参数列表,
@Override
public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4) {List<FunctionArgument> args = FunctionUtils.getFunctionArguments(env);......}
得到的 args 就是参数列表:
[FunctionArgument, index=0, expression="a"]
[FunctionArgument, index=1, expression="b"]
[FunctionArgument, index=2, expression="c"]
[FunctionArgument, index=3, expression="100+2"]
你可以直接从 env
中通过 __args__
变量直接获取:
List<FunctionArgument> args = (List<FunctionArgument>)env.get("__args__");
在 lambda 表达式中也可以捕获参数列表并使用,捕获的调用参数列表存放在 __args__
变量:
List<FunctionArgument> args = (List<FunctionArgument>) AviatorEvaluator.execute("f = lambda(a,bc, d) -> __args__ end; f(1,2,100+2)");assertEquals(3, args.size());
System.out.println(args);
assertEquals(0, args.get(0).getIndex());
assertEquals("1", args.get(0).getExpression());
assertEquals(1, args.get(1).getIndex());
assertEquals("2", args.get(1).getExpression());
assertEquals(2, args.get(2).getIndex());
assertEquals("100+2", args.get(2).getExpression());
利用这一特性,你可以在运行时对调用的参数做参数校验或者分支派发,以及对于函数调用过程做优化,例如对针对参数做结果缓存等等。不过这一特性会对性能带来稍许损失。
语法特性:FEATURE_SET
设置 AviatorScript 支持的语法特性集合,它接受的是一个 Set<Feature>
的集合,Feature 包括:
Assignment
赋值Return
返回语句If
条件语句ForLoop
for 循环语句,包括 break/continue。WhileLoop
while 循环语句,包括 break/continueLet
局部变量定义 let 语句LexicalScope
大括号定义词法作用域Lambda
匿名函数 lambda 定义Fn
命名函数的 fn 定义InternalVars
内部变量,如__instance__
、__env__
等。Module
模块系统,包括exports
和require/load
函数ExceptionHandle
异常处理,包括 try/catch/finally/throw 语句NewInstance
创建对象的 new 语法支持StringInterpolation
字符串插值Use
是否启用use
语法导入 java 类到当前上下文,方便 new 或者 catch 异常类等。StaticFields
是否启用静态字段直接访问,类似Long.MAX_VALUE
等。StaticMethods
是否启用静态方法直接使用(基于反射),类似Math.abs(d)
等
你可以自定义语法特性集合:
/*** Configure engine example** @author dennis(killme2008@gmail.com)**/
public class ConfigureInstanceExample {public static void main(final String[] args) {AviatorEvaluatorInstance instance = AviatorEvaluator.newInstance();instance.setOption(Options.USE_USER_ENV_AS_TOP_ENV_DIRECTLY, false);instance.setOption(Options.FEATURE_SET,Feature.asSet(Feature.Assignment, Feature.ForLoop, Feature.WhileLoop,Feature.Lambda,Feature.Let));System.out.println(instance.execute("let square = lambda(x) -> x*2 end; for x in range(0, 10) { p(square(x)); }"));}
}
这里我们启用了赋值、循环、let 以及 lambda 语法支持,然后执行一个简单脚本。 Feature.asSet
方法方便地生成一个语法特性集合。
如果我们没有启用某个语法特性,执行引擎将报错,比如假设我们将上面的 Feature.Let
移除:
Exception in thread "main" com.googlecode.aviator.exception.UnsupportedFeatureException: Feature.Let is not enabledat com.googlecode.aviator.parser.ExpressionParser.ensureFeatureEnabled(ExpressionParser.java:138)at com.googlecode.aviator.parser.ExpressionParser.statement(ExpressionParser.java:1364)at com.googlecode.aviator.parser.ExpressionParser.statements(ExpressionParser.java:1493)at com.googlecode.aviator.parser.ExpressionParser.parse(ExpressionParser.java:920)at com.googlecode.aviator.AviatorEvaluatorInstance.innerCompile(AviatorEvaluatorInstance.java:1293)at com.googlecode.aviator.AviatorEvaluatorInstance.compile(AviatorEvaluatorInstance.java:1256)at com.googlecode.aviator.AviatorEvaluatorInstance.compile(AviatorEvaluatorInstance.java:1207)at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1383)at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1400)at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1436)at com.googlecode.aviator.example.ConfigureInstanceExample.main(ConfigureInstanceExample.java:24)
这个选项的默认值是 Feature.getFullFeatures()
,也就是启用所有的语法特性,如果你想使用 5.0 之前的兼容模式,只启用赋值、lambda 以及内部变量,可以用 Feature.getCompatibleFeatures()
。
禁用和启用单个选项可以通过 AviatorEvaluatorInstance
的 enableFeature(feature)
和 disableFeature(feature)
方法。