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 包中。其中最核心的是 ScriptEngineManagerScriptEngine 接口。

从 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 找到。


原始标题:Evaluating a Math Expression in Java | Baeldung