龙空技术网

Java表达式求值引擎Aviator(一)

Spring全家桶实战案例 3313

前言:

目前姐妹们对“java 字符串表达式求值怎么写的”大概比较关心,兄弟们都想要知道一些“java 字符串表达式求值怎么写的”的相关内容。那么小编同时在网摘上收集了一些对于“java 字符串表达式求值怎么写的””的相关资讯,希望小伙伴们能喜欢,兄弟们一起来了解一下吧!

环境:Java8 + Aviator5.2.5

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 的嵌套变量访问。函数式风格的 seq 库,操作集合和数组。

Aviator 的限制:

没有 if else、do while 等语句,没有赋值语句,仅支持逻辑表达式、算术表达式、三元表达式和正则匹配。不支持八进制数字字面量,仅支持十进制和十六进制数字字面量。整体结构

Aviator 的结构非常简单,一个典型的求值器的结构。

使用示例

依赖

<dependency>  <groupId>com.googlecode.aviator</groupId>  <artifactId>aviator</artifactId>  <version>5.2.5</version></dependency><dependency>  <groupId>commons-beanutils</groupId>  <artifactId>commons-beanutils</artifactId>  <version>1.9.4</version></dependency><dependency>  <groupId>commons-logging</groupId>  <artifactId>commons-logging</artifactId>  <version>1.2</version></dependency>

示例1:

执行简单的加法运算

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,包括用户传入的变量数值。

示例2:

给表达式传递参数

public class InputParamsExample {	  public static void main(String[] args) {    Map<String, Object> env = new HashMap<String, Object>();    env.put("name", "张三");    String result = (String) AviatorEvaluator.execute(" '你的姓名是' + name ", env) ;    System.out.println(result) ;  }	}

输出:你的姓名是张三。

示例3:

exec 方法

Aviator 2.2 开始新增加一个 exec 方法,可以更方便地传入变量并执行,而不需要构造 env 这个 map 了:

public class ExecParamsExample {	  public static void main(String[] args) {    String myname="dennis";    Object result = AviatorEvaluator.exec(" 'hello ' + name ", myname);    System.out.println(result) ;  }	}

示例4:

调用函数

Aviator 支持函数调用,函数调用的风格类似Lua脚本语法。

public class InvokeFunctionExample {	  public static void main(String[] args) {    Object res1 = AviatorEvaluator.execute("string.length('hello')");    Object res2 = AviatorEvaluator.execute("string.substring('hello',1,2)") ;    Object res3 = AviatorEvaluator.execute("string.contains('hello','ll')") ;    Object res4 = AviatorEvaluator.exec("string.length(name)", "我是中国人") ;    System.out.println(res1 + "\t" + res2 + "\t" + res3 + "\t" + res4) ;  }	}

示例5:

自定义函数

Aviator 除了内置的函数之外,还允许用户自定义函数,只要实现com.googlecode.aviator.runtime.type.AviatorFunction 接口,并注册到 AviatorEvaluator 即可使用

AviatorFunction 接口十分庞大,通常来说你并不需要实现所有的方法,只要根据你的方法的参数个数,继承 AbstractFunction 类并 override 相应方法即可。

自定义函数:

public class AddFunction extends AbstractFunction {	  @Override  public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {    Number left = FunctionUtils.getNumberValue(arg1, env);    Number right = FunctionUtils.getNumberValue(arg2, env);    return new AviatorDouble(left.doubleValue() + right.doubleValue());  }  // 定义(返回)函数的名称。  public String getName() {    return "add";  }	}

注册函数:

public class CustomFunctionExample {	  public static void main(String[] args) {    //注册函数    AviatorEvaluator.addFunction(new AddFunction());    System.out.println(AviatorEvaluator.execute("add(10,100)"));    // 删除函数通过:removeFunction  }	}

示例6:

编译表达式

我们可以自己先编译表达式,返回一个编译的结果,然后传入不同的 env 来复用编译结果,提高性能,这是更推荐的使用方式。

public class CompileExample {  public static void main(String[] args) {    String expression = "a-(b-c) > 100";    // 编译表达式    Expression compiledExp = AviatorEvaluator.compile(expression);    Map<String, Object> env = new HashMap<String, Object>();    env.put("a", 100.3d);    env.put("b", 45);    env.put("c", -199.100d);    // 执行表达式    Boolean result = (Boolean) compiledExp.execute(env);    System.out.println(result);  }}

通过 compile 方法可以将表达式编译成 Expression 的中间对象,当要执行表达式的时候传入env 并调用 Expression 的 execute 方法即可。表达式中使用了括号来强制优先级,这个例子还使用了>用于比较数值大小,比较运算符!=、==、>、>=、<、<=不仅可以用于数值,也可以用于 String、Pattern、Boolean 等等,甚至是任何用户传入的两个都实现了 java.lang.Comparable 接口的对象之间。

示例7:

访问数组和集合

可以通过中括号去访问数组和 java.util.List 对象,可以通过 map.key 访问 java.util.Map 中 key对应的 value。

public class CollectionExample {  public static void main(String[] args) {    List<String> list = new ArrayList<>();    list.add("我是");    list.add("中国人");    int[] array = new int[3];    array[0] = 10;    array[1] = 100;    array[2] = 1000;    final Map<String, Object> map = new HashMap<>();    map.put("date", LocalDate.now());    Map<String, Object> env = new HashMap<>();    env.put("list", list);    env.put("array", array);    env.put("mmap", map);    System.out.println(AviatorEvaluator.execute(				"list[0]+list[1]+'\narray[0]+array[1]+array[2]='+(array[0]+array[1]+array[2]) +' \ntoday is '+ mmap.date ",				env));  }}

下一篇继续结束:三元操作符,正则表达式匹配,日期比较,大数计算和精度等等。。

给个关注+转发呗谢谢

SpringBoot RabbitMQ消息可靠发送与接收

springboot mybatis jpa 实现读写分离

Springboot整合openfeign使用详解

Springboot整合MyBatis参数传值方式

Springboot Security 基础应用 (1)

SpringBoot整合RocketMQ入门示例

Springboot接口幂等性基于token实现方案

SpringBoot项目中Redis之管道技术

SpringBoot2 整合 OAuth2 资源认证(保护)

springboot中定时任务执行Quartz的使用

Springboot自定义消息转换器

Springboot配置文件yml各种复杂对象配置方法

SpringBoot读写分离组件开发详解

SpringBoot这些常用注解你该知道

SpringBoot项目中异步调用接口方式知多少?

springboot 数据安全传输加密与解密

Springboot自定义参数解析器

标签: #java 字符串表达式求值怎么写的 #计算表达式java #java表达式计算 #java算数表达式求值