Master High-Performance Java Expression Evaluation with Aviator
Built on Java 8, Aviator is a lightweight, high-performance expression evaluator that compiles expressions to JVM bytecode, supporting arithmetic, logical, regex, custom functions, and variable binding, while outlining its limitations, usage examples, and integration steps for developers.
Environment
Java 8+ Aviator 5.2.5
Aviator Overview
Aviator is a high‑performance, lightweight Java expression evaluation engine designed for dynamic evaluation of expressions. It aims to be small (≈450 KB with dependencies, 70 KB without) and compiles expressions to Java bytecode, positioning itself between heavyweight script languages like Groovy and ultra‑lightweight engines.
Key Features
Supports most operators: arithmetic, relational, logical, bitwise, regex (=~), ternary (?:) with proper precedence and parentheses.
Function calls and custom functions.
Built‑in regex matching similar to Ruby/Perl with $digit group references.
Automatic type conversion; unsupported conversions raise exceptions.
Variable injection with nested access (e.g., a.b.c).
Functional‑style seq library for collections and arrays.
Limitations
No control‑flow statements such as if/else or loops; only logical, arithmetic, ternary, and regex expressions.
Only decimal and hexadecimal literals are supported (no octal).
Architecture
The engine’s structure is simple, as illustrated below.
Dependency (Maven)
<code><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>
</code>Usage Examples
Simple addition
<code>public class SimpleExample {
public static void main(String[] args) {
Long result = (Long) AviatorEvaluator.execute("1+2+3");
System.out.println(result);
}
}
</code>The result is a Long , because Aviator only supports Long and Double numeric types.
Passing parameters
<code>public class InputParamsExample {
public static void main(String[] args) {
Map<String, Object> env = new HashMap<>();
env.put("name", "张三");
String result = (String) AviatorEvaluator.execute("'你的姓名是' + name", env);
System.out.println(result);
}
}
</code>Output: 你的姓名是张三。
exec method (Aviator 2.2+)
<code>public class ExecParamsExample {
public static void main(String[] args) {
String myname = "dennis";
Object result = AviatorEvaluator.exec("'hello ' + name", myname);
System.out.println(result);
}
}
</code>Function invocation
<code>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);
}
}
</code>Custom function
Implement
com.googlecode.aviator.runtime.type.AviatorFunction(or extend
AbstractFunction) and register it.
<code>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";
}
}
</code> <code>public class CustomFunctionExample {
public static void main(String[] args) {
AviatorEvaluator.addFunction(new AddFunction());
System.out.println(AviatorEvaluator.execute("add(10,100)"));
}
}
</code>Compiling expressions
<code>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<>();
env.put("a", 100.3d);
env.put("b", 45);
env.put("c", -199.100d);
Boolean result = (Boolean) compiledExp.execute(env);
System.out.println(result);
}
}
</code>Compiled expressions can be reused with different environments, improving performance. The engine supports comparison operators (
!=,
==,
>,
>=,
<,
<=) for numbers, strings, patterns, booleans, and any objects implementing
java.lang.Comparable.
Accessing arrays and collections
<code>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;
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));
}
}
</code>The article continues with ternary operators, regex matching, date comparison, big‑number calculations, and precision handling.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.