Java expression evaluation engine Aviator

Environment: Java8 + aviator5 two point five

Introduction to Aviator

Aviator is a high-performance and lightweight expression evaluation engine implemented in java language, which is mainly used for dynamic evaluation of various expressions. Now there are many open source java expression evaluation engines available. Why do you need avatar?
The design goal of Aviator is lightweight and high-performance. Compared with the bulkiness of Groovy and JRuby, Aviator is very small. In addition, the dependent package is only 450K, not counting the dependent package, it is only 70K; Of course, Aviator's syntax is limited. It is not a complete language, but only a small set of languages.
Secondly, the implementation idea of aviator is very different from other lightweight evaluators. Other evaluators generally run by interpretation, while Aviator directly compiles the expression into Java bytecode and gives it to the JVM for execution. In short, aviator is positioned between a heavyweight scripting language such as Groovy and a lightweight expression engine such as ikeexpression.

Aviator feature

  • Most operators are supported, including arithmetic operator, relational operator, logical operator, bit operator, regular matching operator (= ~), ternary expression?:, It also supports the priority of operators and the mandatory priority of parentheses. For details, see the list of operators later.
  • Support function calls and custom functions
  • Built in support of regular expression matching, similar to ruby and Perl matching syntax, and support Ruby like $digit to point to matching groups.
  • Automatic type conversion: when an operation is performed, the operand type will be automatically determined and converted accordingly. If it cannot be converted, an exception will be thrown.
  • It supports incoming variables and nested variable access similar to a.b.c.
  • Functional style seq library, operation set and array.

Aviator limitations:

  • There are no if else, do while and other statements, and no assignment statements. Only logical expressions, arithmetic expressions, ternary expressions and regular matching are supported.
  • Octal numeric literals are not supported. Only decimal and hexadecimal numeric literals are supported.

Overall structure

The structure of Aviator is very simple, a typical evaluator structure.


Use example

rely on


Example 1:

Perform simple addition operations

public class SimpleExample {
  public static void main(String[] args) {
    Long result = (Long) AviatorEvaluator.execute("1+2+3");

The result is Long, not Integer. This is because the numeric type of Aviator only supports Long and Double. Any Integer will be converted to Long and any floating-point number will be converted to Double, including the variable value passed in by the user.

Example 2:

Pass arguments to an expression

public class InputParamsExample {
  public static void main(String[] args) {
    Map<String, Object> env = new HashMap<String, Object>();
    env.put("name", "Zhang San");
    String result = (String) AviatorEvaluator.execute(" 'What's your name' + name ", env) ;
    System.out.println(result) ;

Output: your name is Zhang San.

Example 3:

exec method

Aviator 2.2 adds a new exec method to make it easier to pass in variables and execute them without constructing the 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) ;

Example 4:

Call function

Aviator supports function calls. The style of function calls is similar to Lua script syntax.

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)", "I am Chinese,") ;
    System.out.println(res1 + "\t" + res2 + "\t" + res3 + "\t" + res4) ;

Example 5:

Custom function

In addition to the built-in functions, Aviator also allows users to customize functions as long as they implement them
com.googlecode.aviator.runtime.type.AviatorFunction interface and register it with AviatorEvaluator

The AviatorFunction interface is very large. Generally speaking, you don't need to implement all methods. Just inherit the AbstractFunction class and override the corresponding methods according to the number of parameters of your method.

Custom functions:

public class AddFunction extends AbstractFunction {
  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());
  // Defines (returns) the name of the function.
  public String getName() {
    return "add";

Register function:

public class CustomFunctionExample {
  public static void main(String[] args) {
    //Register function
    AviatorEvaluator.addFunction(new AddFunction());
    // Delete function: removeFunction

Example 6:

Compile expression

We can compile the expression first, return a compiled result, and then pass in different env s to reuse the compiled results and improve the performance. This is the more recommended way to use.

public class CompileExample {
  public static void main(String[] args) {
    String expression = "a-(b-c) > 100";
    // Compile expression
    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);
    // Execute expression
    Boolean result = (Boolean) compiledExp.execute(env);

Through the compile method, the Expression can be compiled into the intermediate object of Expression. When the Expression is to be executed, you can pass in env and call the execute method of Expression. Parentheses are used in the Expression to enforce the priority. In this example, > is also used to compare the value size. The comparison operators! =, = =, >, > =, <<= It can be used not only for numeric values, but also for String, Pattern, Boolean, etc. even the two passed in by any user implement Java Between objects of lang.comparable interface.

Example 7:

Accessing arrays and collections

You can access arrays and Java. Net files through brackets util. List object, you can use map Key to access Java util. The value corresponding to the key in the map.

public class CollectionExample {
  public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("I am");
    int[] array = new int[3];
    array[0] = 10;
    array[1] = 100;
    array[2] = 1000;
    final Map<String, Object> map = new HashMap<>();
    Map<String, Object> env = new HashMap<>();
    env.put("list", list);
    env.put("array", array);
    env.put("mmap", map);
				"list[0]+list[1]+'\narray[0]+array[1]+array[2]='+(array[0]+array[1]+array[2]) +' \ntoday is '+ ",

The next article continues to end: ternary operators, regular expression matching, date comparison, large number calculation and precision, etc..

Give me a follow + forward, thank you




Keywords: Java Programming Lambda Spring Boot Distribution

Added by samvelyano on Fri, 04 Mar 2022 07:11:02 +0200