当前位置: 首页 > news >正文

Aviator表达式语法基础和Java实战表达式(电商应用)

Aviator 表达式语法

Aviator 语法主要借鉴了 Java 语言,因此对于 Java 开发者来说非常容易上手。

1. 基本运算
  • 算术运算:

    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 // 无符号右移
    
2. 数据类型和字面量
  • 整数:

    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 类型的变量来处理日期
    
3. 变量引用
  • 直接引用:

    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']
    
4. 条件表达式 (三元运算符)
  • 基本形式:

    booleanCondition ? valueIfTrue : valueIfFalse
    

    示例:

    score >= 60 ? "及格" : "不及格"
    
5. 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 { ... } } 这种嵌套形式。每个 ifelse 后都需要一个 {} 包裹的代码块。

6. 内置函数

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 官方文档
    
7. 自定义函数

你可以通过 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 {@Overridepublic 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());}@Overridepublic String getName() {return "myAdd"; // 函数名}
}// 在 main 方法中注册
// AviatorEvaluator.addFunction(new MyAddFunction());// 在表达式中调用
// myAdd(a, b)
8. 集合(List)和 Map 字面量

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 也可以不加引号,如果它符合变量命名规则
    
9. 序列操作 (Seq 模块)

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 或你定义的变量名来引用当前元素。

10. 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 定义了一个匿名函数。

11. 错误处理

Aviator 表达式在执行过程中如果遇到错误(如类型不匹配、变量不存在),会抛出 com.googlecode.aviator.exception.ExpressionRuntimeException 或其子类。


使用示例总结

一个典型的 Aviator 表达式使用流程:

  1. 定义表达式字符串。
  2. 通过 AviatorEvaluator.compile(expressionString) 编译表达式。 (强烈推荐,特别是重复执行的表达式)
  3. 创建环境变量 Map<String, Object>,将表达式中需要用到的变量放入其中。
  4. 通过 compiledExpression.execute(env) 执行表达式,获取结果。

数据类型

  • Number类型:数字类型,支持两种类型,分别对应Java的Long和Double,也就是说任何整数都将被转换为Long,而任何浮点数都将被转换 为Double,包括用户传入的数值也是如此转换。不支持科学计数法,仅支持十进制。如-1、100、2.3等。
  • String类型:字符串类型,单引号或者双引号括起来的文本串,如’helloworld’,变量如果传入的是String或者Character也将转为String类型。任何类型和 String 相加还是 String。
  • Bool类型:常量true和false,表示真值和假值,与java的Boolean.TRUE和Boolean.False对应。
  • Pattern类型: 类似Ruby、perl的正则表达式,以//括起来的字符串,如/\d+/,内部实现为java.util.Pattern。
  • 变量类型:与Java的变量命名规则相同,变量的值由用户传入,如"a"、"b"等
  • nil类型:常量nil,类似java中的null,但是nil比较特殊,nil不仅可以参与==、!=的比较,也可以参与>、>=、<、<=的比较,Aviator规定任何类型 都n大于nil除了nil本身,nil==nil返回true。用户传入的变量值如果为null,那么也将作为nil处理,nil打印为null。

实战场景

该场景为电商系统中的价格计算,在用户结账的时候会涉及许多内容,包括是不是会员、是什么等级的会员、有无优惠卷、当前的营销活动等内容,最终的价格受这些因素的影响。以下,选取了三个场景进行模拟。

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 = 280System.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 = 420System.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);}
}

相关文章:

  • MDP中的events部分
  • leetcode0513. 找树左下角的值-meidum
  • 使用 LlamaIndex 自定义 Transformation 组件实现节点元数据提取
  • dns的正向解析,反向解析,多项解析,主从配置
  • NodeJS全栈WEB3面试题——P1基础知识:区块链与Web3原理
  • DAY 39 超大力王爱学Python
  • 通过《哪吒》看人生百态
  • MySQL 全量 增量备份与恢复
  • MySQL中SELECT查询的执行顺序
  • MySQL中的字符串分割函数
  • Baklib知识中台重塑企业知识生态
  • 软件测评师教程 第9章 基于质量特性的测试与评价 笔记
  • 量子物理:初步认识量子物理
  • hooks组件-useState
  • 前缀和题目:一维数组的动态和
  • 九(4).存在指针的引用,不存在引用的指针
  • RNN循环网络:给AI装上“记忆“(superior哥AI系列第5期)
  • YOLOV7改进之融合深浅下采样模块(DSD Module)和轻量特征融合模块(LFI Module)
  • ubuntu 添加应用到启动菜单
  • CppCon 2014 学习:Hardening Your Code
  • 提高网站的访问速度/什么是关键词搜索
  • 有哪些专做旅游定制的网站/网站推广郑州
  • wordpress小米商城主题/铜川网站seo
  • 微积壹佰 网站建设/校园推广方案
  • 郑州网站建设哪家最好/百度拉新推广平台
  • 做农产品交易网站有哪些/seo课堂