[toc]
概述
Aviator是一个开源的Java表达式求值器,不仅支持四则运算、三元运算、逻辑运算,而且其强大的接口支持自定义扩展函数。鉴于此,我原先的研发团队结合公司业务场景,选择了这个google的计算引擎,为了扩展我们业务需求,定义了一系列自定义函数,以支撑我们业务场景。
特性
数据类型
Number类型
:数字类型,支持两种类型,分别对应Java的Long和Double,也就是说任何整数都将被转换为Long,而任何浮点数都将被转换 为Double,包括用户传入的数值也是如此转换。不支持科学计数法,仅支持十进制。如-1、100、2.3等。String类型
:字符串类型,单引号或者双引号括起来的文本串,如’helloworld’,变量如果传入的是String或者Character也将转为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。
操作类型
算术运算符
Aviator支持常见的算术运算符,包括+ - * / % 五个二元运算符,和一元运算符"-"。其中 - * / %和一元的"-"仅能作用于Number类型。 "+"不仅能用于Number类型,还可以用于String的相加,或者字符串与其他对象的相加。Aviator规定,任何类型与String相加,结果为String。
逻辑运算符
Avaitor的支持的逻辑运算符包括,一元否定运算符"!",以及逻辑与的"&&",逻辑或的"||"。逻辑运算符的操作数只能为Boolean。 关系运算符
Aviator支持的关系运算符包括"<" “<=” “>” “>=” 以及"==“和”!=" 。 &&和||都执行短路规则。
关系运算符可以作用于Number之间、String之间、Pattern之间、Boolean之间、变量之间以及其他类型与nil之间的关系比较,不同类型除了nil之 外不能相互比较。
Aviator规定任何对象都比nil大除了nil之外。
位运算符
Aviator支持所有的Java位运算符,包括"&" “|” “^” “~” “>>” “<<” “>>>”。
匹配运算符
匹配运算符"=~"用于String和Pattern的匹配,它的左操作数必须为String,右操作数必须为Pattern。匹配成功后,Pattern的分组将存于变量 $num,num为分组索引。
三元运算符
Aviator没有提供if else语句,但是提供了三元运算符 “?:”,形式为 bool ? exp1: exp2。 其中bool必须为结果为Boolean类型的表达式,而exp1和 exp2可以为任何合法的Aviator表达式,并且不要求exp1和exp2返回的结果类型一致。
扩展特性
数字扩展
1、多个数字求和:sum
对多个数字进行求和,忽略空值,作为0处理,提供兼容。
示例代码:
/**
* @description: 多个数字求和计算(其中任何一个数字为空则作为0处理)
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class SumTest {
@Test
public void test(){
Map<String,Object> evn = new HashMap<String,Object>(){{
put("x",2);
put("y",4);
put("z",8);
}};
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("sum(x,y,z,h)").env(evn).build()));
}
}
复制代码
输出:
14
复制代码
2、多个数字获取最大值:max
对多个数字获取最大值,忽略空值,作为0处理,提供兼容。
示例代码:
/**
* @description: 多个数字求最大值(其中任何一个数字为空则作为0处理)
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class MaxTest {
@Test
public void test(){
Map<String,Object> evn = new HashMap<String,Object>(){{
put("x",2);
put("y",4);
put("z",8);
}};
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("max(x,y,z,h)").env(evn).build()));
}
}
复制代码
输出:
8
复制代码
3、多个数字获取最大值:min
对多个数字获取最小值,忽略空值,作为0处理,提供兼容。
示例代码:
/**
* @description: 多个数字求最小值(其中任何一个数字为空则作为0处理)
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class MinTest {
@Test
public void test(){
Map<String,Object> evn = new HashMap<String,Object>(){{
put("x",2);
put("y",4);
put("z",8);
}};
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("min(x,y,z,h)").env(evn).build()));
}
}
复制代码
输出:
2
复制代码
4、向上取整:ceil
向上取整
示例代码:
/**
* @description: 向上取整
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class CeilTest {
@Test
public void test(){
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(1.2)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(1.6)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(201)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(196)").env(Collections.emptyMap()).build()));
}
}
复制代码
输出:
2.0
2.0
201.0
196.0
复制代码
5、向下取整:floor
向上取整
示例代码:
/**
* @description: 向下取整
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class FloorTest {
@Test
public void test(){
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(1.2)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(1.6)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(201)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(196)").env(Collections.emptyMap()).build()));
}
}
复制代码
输出:
1.0
1.0
201.0
196.0
复制代码
6、四舍五入:round
四舍五入
示例代码:
/**
* @description: 四舍五入
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class RoundTest {
@Test
public void test(){
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(1.2)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(1.6)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(201)").env(Collections.emptyMap()).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(196)").env(Collections.emptyMap()).build()));
}
}
复制代码
输出:
1
2
201
196
复制代码
7、精度处理:scale
精度处理,具体参数说明查看 org.suze.aviator.function.number.Scale
示例代码:
/**
* @description: 对数字取整方式 和 精度进位 处理
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class ScaleTest {
@Test
public void test(){
Map<String,Object> evn = new HashMap<String,Object>(){{
put("x",15.344);
}};
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,0,0)").env(evn).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,0,1)").env(evn).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,0,2)").env(evn).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,-2,1)").env(evn).build()));
System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,-2,2)").env(evn).build()));
}
}
复制代码
输出:
15
16
15
100
0
复制代码
集合扩展
1、判断一个字符串是否在一个字符串区间集合中:in(finder,delimiter,values)
判断一个字符串是否在一个字符串区间集合中,finder代表查找项,delimiter字符串分隔符,values以delimiter分割的字符串。
示例代码:
/**
* @description: 判断一个字符串是否在一个字符串区间集合中
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class InTest {
@Test
public void test(){
Map<String,Object> evn = new HashMap<String,Object>(){{
put("x",15);
}};
String expression = "in(x, ',' , '15,34,22')";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build();
System.out.println(AviatorExecutor.executeBoolean(ctx));
}
}
复制代码
输出:
true
复制代码
2、判断一个字符串是否不在一个字符串区间集合中:notin(finder,delimiter,values)
判断一个字符串是否不在一个字符串区间集合中,finder代表查找项,delimiter字符串分隔符,values以delimiter分割的字符串。
示例代码:
/**
* @description: 判断一个字符串是否在一个字符串区间集合中
* @Date : 2021/4/11 9:43 AM
* @Author : 石冬冬-Seig Heil
*/
public class InTest {
@Test
public void test(){
Map<String,Object> evn = new HashMap<String,Object>(){{
put("x",15);
}};
String expression = "notin(x, ',' , '15,34,22')";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build();
System.out.println(AviatorExecutor.executeBoolean(ctx));
}
}
复制代码
输出:
false
复制代码
通用函数
基于日常业务场景需求,扩展的相关自定义函数。
1、两日期相差天数,参数类型为date:days.diff(current,destination)
两日期相差天数,参数类型为date
示例代码:
/**
* @description: 两日期相差天数,参数类型为date
* @Date : 2021/4/11 10:19 AM
* @Author : 石冬冬-Seig Heil
*/
public class DiffDaysTest {
@SneakyThrows
@Test
public void test(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Map<String,Object> evn = new HashMap<String,Object>(){{
put("current",simpleDateFormat.parse("2021-04-11"));
put("destination",simpleDateFormat.parse("2020-04-11"));
}};
String expression = "days.diff(current,destination)";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build();
System.out.println( AviatorExecutor.executeBigDecimal(ctx));
}
}
复制代码
输出:
365
复制代码
2、获取生日年龄:age(date)
根据出生年月日计算年龄,出生年月日类型为字符串
示例代码:
/**
* @description: 根据出生年月日计算年龄,出生年月日类型为字符串
* @Date : 2021/4/11 10:19 AM
* @Author : 石冬冬-Seig Heil
*/
public class AgeTest {
@SneakyThrows
@Test
public void test(){
Map<String,Object> evn = new HashMap<String,Object>(){{
put("birth","19880808");
}};
String expression = "age(birth)";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build();
System.out.println("age:" + AviatorExecutor.execute(ctx));
}
}
复制代码
输出:
32
复制代码
3、截取字符串中的数字求和:string.numbers.sum
截取字符串中的数字求和
示例代码:
/**
* @description: 截取字符串中的数字求和
* @Date : 2021/4/11 10:19 AM
* @Author : 石冬冬-Seig Heil
*/
public class StringNumbersSumTest {
@SneakyThrows
@Test
public void test(){
String str = "保费借款金额:人民币(第一年:5600.00元;第二年:1110.00元;第三年:1000.00元)";
Map<String,Object> evn = new HashMap<String,Object>(){{
put("str",str);
}};
String expression = "string.numbers.sum(str, '-', ':', '元')";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).cached(false).build();
System.out.println(AviatorExecutor.execute(ctx));
}
}
复制代码
输出:
7710.00
复制代码
4、数字转大写金额:chinese.number.upper(num)
截取字符串中的数字求和
示例代码:
/**
* @description: 数字转大写金额
* @Date : 2021/4/11 10:19 AM
* @Author : 石冬冬-Seig Heil
*/
public class ChineseNumberUpperTest {
@SneakyThrows
@Test
public void test(){
BigDecimal num = new BigDecimal("11111.01");
Map<String,Object> evn = new HashMap<String,Object>(){{
put("num",num);
}};
String expression = "chinese.number.upper(num)";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build();
System.out.println(AviatorExecutor.execute(ctx));
}
}
复制代码
输出:
壹万壹仟壹佰壹拾壹元零壹分
复制代码
对象函数
为空时,设置一个默认值
1、为空时,设置一个默认值:nvl(value,defaultValue)
两日期相差天数,参数类型为date
示例代码:
/**
* @description: 根据出生年月日计算年龄,出生年月日类型为字符串
* @Date : 2021/4/11 10:19 AM
* @Author : 石冬冬-Seig Heil
*/
public class NvlTest {
@SneakyThrows
@Test
public void test(){
String expression = "nvl(a,0)";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build();
System.out.println(AviatorExecutor.executeBigDecimal(ctx));
}
}
复制代码
输出:
0
复制代码
2、字符串转数字:objects.toNumber(value,defaultValue)
字符串转数字,如果字符串为空,则使用默认值作为返回值,objects.toNumber(value,defaultValue)
示例代码:
/**
* @description: objects.toNumber(x,y)
* @Date : 2021/4/11 10:19 AM
* @Author : 石冬冬-Seig Heil
*/
public class ToNumberTest {
@SneakyThrows
@Test
public void test(){
String expression = "objects.toNumber('1',0)";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build();
System.out.println(AviatorExecutor.executeBigDecimal(ctx));
}
}
复制代码
输出:
1
复制代码
3、数字转字符串:objects.toString(value,defaultValue)
数字转字符串,如果数字为空,则使用默认值作为返回值,objects.toString(value,defaultValue)
示例代码:
/**
* @description: 数字转字符串,如果数字为空,则使用默认值作为返回值,objects.toString(value,defaultValue)
* @Date : 2021/4/11 10:19 AM
* @Author : 石冬冬-Seig Heil
*/
public class ToStringTest {
@SneakyThrows
@Test
public void test(){
String expression = "objects.toString(1,'0')";
AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build();
System.out.println(AviatorExecutor.executeBigDecimal(ctx));
}
}
复制代码
输出:
1
复制代码
高级特性
示例代码:
/**
* @description: 基于Aviator测试类
* @Date : 2018/9/7 下午6:00
* @Author : 石冬冬-Seig Heil(shiyongxin2010@163.com)
*/
@Slf4j
public class AviatorObjectTest {
@Test
public void object_instance(){
Teacher teacher = new Teacher(){{
setName("im");
setScore(20);
}};
Student student = new Student(){{
setName("Jack");
setScore(22);
}};
Map<String,Object> env = new HashMap<String,Object>(){{
put("teacher",teacher);
put("student",student);
}};
Object value = AviatorExecutor.execute(AviatorContext.builder().env(env).expression("student.name").build());
System.out.println(value);
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Colleague {
private String name;
private double score;
}
@Data
@NoArgsConstructor
public class Student extends Colleague {
public Student(String name, double score) {
super(name, score);
}
}
@Data
@NoArgsConstructor
public class Teacher extends Colleague {
}
}
复制代码
输出:
Jack
复制代码
近期评论