1. 概述
本文将介绍几种在 Java 中对数学表达式进行求值的方法。这个功能在一些需要动态执行字符串形式表达式的项目中非常实用。
我们会先介绍几个第三方库及其使用方式,然后看看如何使用 Java 内置的脚本 API 来完成这项任务。
2. exp4j
exp4j 是一个开源库,用于计算数学表达式和函数。它基于 Dijkstra 的调度场算法(Shunting Yard Algorithm),可以解析以中缀表示法书写的表达式。
除了支持标准运算符和函数外,exp4j 还允许我们自定义运算符和函数。
2.1. 添加 Maven 依赖
要使用 exp4j,我们需要在项目中添加 Maven 依赖:
<dependency>
<groupId>net.objecthunter</groupId>
<artifactId>exp4j</artifactId>
<version>0.4.8</version>
</dependency>
2.2. 计算简单表达式
我们可以直接用字符串形式提供一个简单的数学表达式:
@Test
public void givenSimpleExpression_whenCallEvaluateMethod_thenSuccess() {
Expression expression = new ExpressionBuilder("3+2").build();
double result = expression.evaluate();
Assertions.assertEquals(5, result);
}
上面代码中,我们首先创建了一个 ExpressionBuilder
实例,然后通过它构建出 Expression
对象并调用 evaluate()
方法进行求值。
2.3. 在表达式中使用变量
接下来我们给表达式加上变量:
@Test
public void givenTwoVariables_whenCallEvaluateMethod_thenSuccess() {
Expression expression = new ExpressionBuilder("3x+2y")
.variables("x", "y")
.build()
.setVariable("x", 2)
.setVariable("y", 3);
double result = expression.evaluate();
Assertions.assertEquals(12, result);
}
这里我们通过 .variables("x", "y")
声明了两个变量,并用 .setVariable()
方法为它们赋值。✅ 变量数量不限,想加多少加多少。
2.4. 包含数学函数的表达式
exp4j 也支持常见的数学函数,比如三角函数:
@Test
public void givenMathFunctions_whenCallEvaluateMethod_thenSuccess() {
Expression expression = new ExpressionBuilder("sin(x)*sin(x)+cos(x)*cos(x)")
.variables("x")
.build()
.setVariable("x", 0.5);
double result = expression.evaluate();
Assertions.assertEquals(1, result);
}
3. Javaluator
Javaluator 是另一个免费、轻量级且独立的表达式求值库。和 exp4j 类似,它也支持中缀表达式的解析与计算。
3.1. 添加 Maven 依赖
要使用 Javaluator,我们需要添加如下 Maven 依赖:
<dependency>
<groupId>com.fathzer</groupId>
<artifactId>javaluator</artifactId>
<version>3.0.3</version>
</dependency>
3.2. 计算简单表达式
使用 Javaluator 需要创建一个 DoubleEvaluator
实例:
@Test
public void givenExpression_whenCallEvaluateMethod_thenSuccess() {
String expression = "3+2";
DoubleEvaluator eval = new DoubleEvaluator();
Double result = eval.evaluate(expression);
Assertions.assertEquals(5, result);
}
3.3. 含有变量的表达式
如果表达式中有变量,我们需要借助 StaticVariableSet
来管理它们:
@Test
public void givenVariables_whenCallEvaluateMethod_thenSuccess() {
String expression = "3*x+2*y";
DoubleEvaluator eval = new DoubleEvaluator();
StaticVariableSet<Double> variables = new StaticVariableSet<Double>();
variables.set("x", 2.0);
variables.set("y", 3.0);
Double result = eval.evaluate(expression, variables);
Assertions.assertEquals(12, result);
}
使用 .set()
方法设置变量的值即可。
3.4. 含有数学函数的表达式
Javaluator 同样支持数学函数的计算:
@Test
public void givenMathFunction_whenCallEvaluateMethod_thenSuccess() {
String expression = "sin(x)*sin(x)+cos(x)*cos(x)";
DoubleEvaluator eval = new DoubleEvaluator();
StaticVariableSet<Double> variables = new StaticVariableSet<Double>();
variables.set("x", 0.5);
Double result = eval.evaluate(expression, variables);
Assertions.assertEquals(1, result);
}
4. 使用 Java 脚本 API
前面介绍了两个第三方库,现在我们来看看如何使用 Java 自带的脚本 API 实现类似功能。
Java 提供了强大的脚本支持,相关类都在 javax.script
包中。其中最核心的是 ScriptEngineManager
和 ScriptEngine
接口。
从 Java 8 开始,默认使用的 JavaScript 引擎是 Nashorn,比之前的 Rhino 更快更强。
4.1. 获取 ScriptEngine 实例
我们需要先创建一个 ScriptEngineManager
,再从中获取 ScriptEngine
实例:
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
⚠️ 注意:Nashorn 是 JDK 自带的默认 JavaScript 引擎。
4.2. 计算简单表达式
获取到 scriptEngine
后,可以直接调用 eval()
方法:
String expression = "3+2";
Integer result = (Integer) scriptEngine.eval(expression);
Assertions.assertEquals(5, result);
4.3. 含有变量的表达式
对于含变量的表达式,我们可以在 JavaScript 中直接声明和初始化变量:
String expression = "x=2; y=3; 3*x+2*y;";
Double result = (Double) scriptEngine.eval(expression);
Assertions.assertEquals(12, result);
✅ 因为是 JavaScript 引擎,所以语法上更自由灵活。
⚠️ 但要注意一点:JavaScript 并没有直接提供数学函数接口,必须通过 Math 对象调用,因此不能像前面两个库那样直接处理数学函数表达式。
5. 总结
在这篇文章中,我们探讨了几种在 Java 中对数学表达式进行求值的方式:
- ✅ 第三方库:exp4j、Javaluator —— 简单粗暴,功能完整
- ⚠️ Java Scripting API —— 利用 Nashorn 引擎,但对数学函数支持有限
完整示例代码可在 GitHub 找到。