Aviator 语法主要借鉴了 Java 语言,因此对于 Java 开发者来说非常容易上手。
算术运算:
1 + 2 - 3 * 4 / 5 % 6 // 加、减、乘、除、取模
-10 // 负数
比较运算:
a > b
a < b
a >= b
a <= b
a == b // 相等
a != b // 不等
逻辑运算:
a && b // 逻辑与 (and)
a || b // 逻辑或 (or)
!a // 逻辑非 (not)
位运算:
a & b // 按位与
a | b // 按位或
a ^ b // 按位异或
~a // 按位非
a << b // 左移
a >> b // 右移
a >>> b // 无符号右移
整数:
123
0xFF // 十六进制
077 // 八进制 (注意:在 Aviator 5.0+ 中,推荐使用 0o77 表示八进制)
浮点数 (double):
123.45
.5
1.2e3 // 科学计数法
长整数 (long):
123L // 以 L 结尾表示长整数
布尔值:
true
false
字符串:
"hello world"
'hello world' // 单引号和双引号都支持
"a\"b" // 转义字符
BigDecimal (高精度浮点数):
1.23M // 以 M 结尾表示 BigDecimal 类型
100M // 整数也可以是 BigDecimal 类型
nil (空值):
nil // 相当于 Java 的 null
日期:
"2023-01-01 12:00:00" // 字符串形式会被自动解析为 Date 类型(需要配置日期格式化器)
// 通常通过传入 Date 类型的变量来处理日期
直接引用:
myVariable // 引用 Map 中 key 为 "myVariable" 的值
访问对象属性:
user.name // 访问 user 对象的 name 属性(等同于 user.getName())
order.customer.address.city // 链式访问
访问 Map 元素:
map.key // 访问 Map 中 key 为 "key" 的值 (等同于 map.get("key"))
// 注意:如果 key 是非法的变量名(如包含特殊字符),需要用方括号:
map['my-key']
基本形式:
booleanCondition ? valueIfTrue : valueIfFalse
示例:
score >= 60 ? "及格" : "不及格"
if-else
语句 (代码块)基本形式:
if (condition) {
// block for true
} else {
// block for false
}
嵌套 if-else if-else
:
if (age < 18) {
"青少年"
} else {
if (age >= 18 && age < 60) {
"成年人"
} else {
"老年人"
}
}
注意: Aviator 的 else if
实际上是 else { if { ... } else { ... } }
这种嵌套形式。每个 if
和 else
后都需要一个 {}
包裹的代码块。
Aviator 提供了丰富的内置函数,例如:
数学函数:
math.abs(-10)
math.max(a, b)
math.min(a, b)
math.round(3.14)
math.pow(2, 3)
math.sqrt(9)
字符串函数:
string.length("hello")
string.contains("hello", "ell")
string.startsWith("hello", "he")
string.endsWith("hello", "lo")
string.substring("hello", 1, 3) // 从索引1开始,长度为3
string.split("a,b,c", ",")
集合/序列操作:
count (统计元素数量):
count([1, 2, 3]) // 返回 3
count(users) // 如果 users 是 List/Set,返回其大小
**isEmpty (判断是否为空):
isEmpty([]) // 返回 true
isEmpty(nil) // 返回 true
**include (判断是否包含):
include([1, 2, 3], 2) // 返回 true
include(myString, "sub") // 字符串包含子串
序列操作:
seq.add([1,2], 3) // 返回 [1,2,3]
seq.remove([1,2,3], 2) // 返回 [1,3]
seq.contains([1,2,3], 2) // 返回 true
seq.size([1,2,3]) // 返回 3
**类型转换函数:
long(10.5) // 转换为 long
double(10) // 转换为 double
str(123) // 转换为字符串
// 更多转换函数:bigdec(), date() 等
**其他常用函数:
type(obj) // 获取变量的类型
nil_or_empty(obj) // 判断是否为 nil 或空(字符串、集合、Map等)
// ...还有很多,请查阅 Aviator 官方文档
你可以通过 AviatorEvaluator.addFunction()
方法注册自定义的 Java 函数,然后在表达式中像内置函数一样调用。
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorLong;
import com.googlecode.aviator.runtime.type.AviatorObject;
import java.util.Map;
// 自定义加法函数
class MyAddFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
Number num1 = FunctionUtils.getNumberValue(arg1, env);
Number num2 = FunctionUtils.getNumberValue(arg2, env);
return AviatorLong.valueOf(num1.longValue() + num2.longValue());
}
@Override
public String getName() {
return "myAdd"; // 函数名
}
}
// 在 main 方法中注册
// AviatorEvaluator.addFunction(new MyAddFunction());
// 在表达式中调用
// myAdd(a, b)
Aviator 5.0+ 支持 List 和 Map 的字面量表示:
List 字面量:
[1, 2, "hello", true]
[1 + 2, max(a, b)] // 元素可以是表达式
**Map 字面量:
#{ "name": "张三", "age": 30, "isValid": true }
#{ key1: value1, key2: value2 } // key 也可以不加引号,如果它符合变量命名规则
Aviator 5.0+ 引入了强大的序列操作,支持对 List、Set、数组等进行过滤、求和、映射等操作。
**过滤 (filter):
filter(users, "user.age > 18 && user.gender == 'male'") // 过滤 age > 18 且 gender 为 male 的用户
**映射 (map):
map(users, "user.name") // 提取所有用户的 name 属性
求和 (sum):
sum(items, "item.price * item.quantity") // 计算所有商品的总价
**所有满足 (every):
every(numbers, "num > 0") // 判断所有数字是否都大于0
**任一满足 (some):
some(users, "user.vip == true") // 判断是否存在VIP用户
**排序 (sort):
sort(products, "product.price desc") // 按价格降序排序
注意: 序列操作的第二个参数是一个表达式字符串,其中可以通过 element
或你定义的变量名来引用当前元素。
lambda
表达式 (匿名函数)Aviator 5.0+ 支持 lambda 表达式,可以作为函数参数传递。
filter(users, lambda user : user.age > 18 end) // 等同于上面的 filter 示例
map(items, lambda item : item.price * item.quantity end)
其中 lambda arg1, arg2 : expression end
定义了一个匿名函数。
Aviator 表达式在执行过程中如果遇到错误(如类型不匹配、变量不存在),会抛出 com.googlecode.aviator.exception.ExpressionRuntimeException
或其子类。
一个典型的 Aviator 表达式使用流程:
AviatorEvaluator.compile(expressionString)
编译表达式。 (强烈推荐,特别是重复执行的表达式)Map
,将表达式中需要用到的变量放入其中。compiledExpression.execute(env)
执行表达式,获取结果。该场景为电商系统中的价格计算,在用户结账的时候会涉及许多内容,包括是不是会员、是什么等级的会员、有无优惠卷、当前的营销活动等内容,最终的价格受这些因素的影响。以下,选取了三个场景进行模拟。
package cn.srw;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// 1. 基础价格表达式 (商品单价 * 购买数量)
String basePriceExp = "price * quantity";
// ! 加M表示告诉表达式引擎 返回的是一个BigDecimal对象
// 2. 会员折扣表达式 (根据会员等级应用折扣)
String memberDiscountExp = "if (memberLevel == 'GOLD') { basePrice * 0.9M } " +
"else { " +
" if (memberLevel == 'PLATINUM') { basePrice * 0.8M } " +
" else { basePrice } " +
"}";
// 3. 满减活动表达式 (根据满足的金额减去相应金额)
String fullReductionExp = "if (totalAfterMemberDiscount >= 500) { totalAfterMemberDiscount - 60M } " +
"else { " +
" if (totalAfterMemberDiscount >= 200) { totalAfterMemberDiscount - 20M } " +
" else { totalAfterMemberDiscount } " +
"}";
// 4. 最终价格表达式 (减去优惠券面值)
String finalPriceExp = "totalAfterFullReduction - couponValue";
// --- 预编译表达式 (推荐做法,提高性能) ---
Expression compiledBasePriceExp = AviatorEvaluator.compile(basePriceExp);
Expression compiledMemberDiscountExp = AviatorEvaluator.compile(memberDiscountExp);
Expression compiledFullReductionExp = AviatorEvaluator.compile(fullReductionExp);
Expression compiledFinalPriceExp = AviatorEvaluator.compile(finalPriceExp);
// --- 模拟计算场景 ---
// 场景1: 普通用户,无优惠券
System.out.println("--- 场景1: 普通用户,无优惠券 ---");
Map<String, Object> env1 = new HashMap<>();
env1.put("price", new BigDecimal("100"));
env1.put("quantity", 3);
env1.put("memberLevel", "NONE"); // 普通用户
env1.put("couponValue", new BigDecimal("0"));
calculateAndPrintPrice(env1, compiledBasePriceExp, compiledMemberDiscountExp, compiledFullReductionExp, compiledFinalPriceExp);
// 预期结果: 100 * 3 = 300; 300 >= 200 减 20 = 280; 280 - 0 = 280
System.out.println("\n--- 场景2: 黄金会员,有优惠券 ---");
// 场景2: 黄金会员,有优惠券
Map<String, Object> env2 = new HashMap<>();
env2.put("price", new BigDecimal("100"));
env2.put("quantity", 5);
env2.put("memberLevel", "GOLD"); // 黄金会员
env2.put("couponValue", new BigDecimal("10"));
calculateAndPrintPrice(env2, compiledBasePriceExp, compiledMemberDiscountExp, compiledFullReductionExp, compiledFinalPriceExp);
// 预期结果: 100 * 5 = 500; 黄金会员 500 * 0.9 = 450; 450 >= 200 减 20 = 430; 430 - 10 = 420
System.out.println("\n--- 场景3: 白金会员,大额订单,无优惠券 ---");
// 场景3: 白金会员,大额订单,无优惠券
Map<String, Object> env3 = new HashMap<>();
env3.put("price", new BigDecimal("200"));
env3.put("quantity", 4);
env3.put("memberLevel", "PLATINUM"); // 白金会员
env3.put("couponValue", new BigDecimal("0"));
calculateAndPrintPrice(env3, compiledBasePriceExp, compiledMemberDiscountExp, compiledFullReductionExp, compiledFinalPriceExp);
// 预期结果: 200 * 4 = 800; 白金会员 800 * 0.8 = 640; 640 >= 500 减 60 = 580; 580 - 0 = 580
}
/**
* 计算并打印价格
*
* @param env 环境变量 Map
* @param compiledBasePriceExp 基础价格表达式
* @param compiledMemberDiscountExp 会员折扣表达式
* @param compiledFullReductionExp 满减活动表达式
* @param compiledFinalPriceExp 最终价格表达式
*/
private static void calculateAndPrintPrice(
Map<String, Object> env,
Expression compiledBasePriceExp,
Expression compiledMemberDiscountExp,
Expression compiledFullReductionExp,
Expression compiledFinalPriceExp) {
// 1. 计算基础价格
BigDecimal basePrice = (BigDecimal) compiledBasePriceExp.execute(env);
env.put("basePrice", basePrice); // 将结果放入环境变量供后续表达式使用
System.out.println(" 基础价格: " + basePrice);
// 2. 计算会员折扣后的价格
BigDecimal totalAfterMemberDiscount = (BigDecimal) compiledMemberDiscountExp.execute(env);
env.put("totalAfterMemberDiscount", totalAfterMemberDiscount);
System.out.println(" 会员折扣后价格: " + totalAfterMemberDiscount);
// 3. 计算满减活动后的价格
BigDecimal totalAfterFullReduction = (BigDecimal) compiledFullReductionExp.execute(env);
env.put("totalAfterFullReduction", totalAfterFullReduction);
System.out.println(" 满减活动后价格: " + totalAfterFullReduction);
// 4. 计算最终支付价格
BigDecimal finalPrice = (BigDecimal) compiledFinalPriceExp.execute(env);
System.out.println(" 最终支付价格: " + finalPrice);
}
}