在Java开发中,动态解析并计算数学表达式字符串是一个常见需求,比如处理用户自定义的计算公式、动态配置的业务规则等场景。手动实现表达式词法分析、语法解析和计算过程逻辑复杂,容易引入错误,而Java内置的JavaScript引擎可以直接执行符合JavaScript语法的数学表达式,大幅降低实现成本。

Java中可用的JavaScript引擎
Java从JDK 1.6开始就内置了JavaScript引擎支持,不同JDK版本对应的引擎有所区别:
- JDK 1.6到JDK 1.7:默认使用Rhino引擎,由Mozilla提供
- JDK 1.8:默认使用Nashorn引擎,是Oracle推出的新一代JavaScript引擎,性能优于Rhino
- JDK 9及之后版本:Nashorn引擎被标记为废弃,JDK 15之后正式移除,需要手动引入第三方引擎如GraalVM JavaScript引擎
基于ScriptEngineManager实现表达式计算
Java提供了javax.script包来支持脚本引擎的调用,核心类包括ScriptEngineManager和ScriptEngine,我们可以通过这些类获取JavaScript引擎并执行表达式。
基础计算实现
以下是一个简单的示例,演示如何计算基本的数学表达式:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class MathExpressionCalculator {
public static void main(String[] args) {
// 创建脚本引擎管理器
ScriptEngineManager manager = new ScriptEngineManager();
// 获取JavaScript引擎,参数传入"JavaScript"或者"nashorn"等引擎名称
ScriptEngine engine = manager.getEngineByName("JavaScript");
// 待计算的数学表达式字符串
String expression = "3 + 5 * (2 - 4) / 2";
try {
// 执行表达式并获取结果
Object result = engine.eval(expression);
System.out.println("表达式 " + expression + " 的计算结果为:" + result);
} catch (ScriptException e) {
System.out.println("表达式计算失败,错误信息:" + e.getMessage());
}
}
}
上述代码中,首先通过ScriptEngineManager获取JavaScript引擎,然后调用eval方法执行表达式字符串,执行成功后会返回计算结果,如果表达式语法错误则会抛出ScriptException。
支持变量和复杂表达式
JavaScript引擎还支持在表达式中引入变量,我们可以先定义变量再执行包含变量的表达式:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.HashMap;
import java.util.Map;
public class VariableExpressionCalculator {
public static void main(String[] args) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
// 定义变量和对应的值
Map<String, Object> variables = new HashMap<>();
variables.put("a", 10);
variables.put("b", 20);
variables.put("c", 5);
// 包含变量的表达式
String expression = "a * b + c / 2";
try {
// 先向引擎中注入变量
for (Map.Entry<String, Object> entry : variables.entrySet()) {
engine.put(entry.getKey(), entry.getValue());
}
// 执行表达式
Object result = engine.eval(expression);
System.out.println("带变量的表达式计算结果:" + result);
} catch (ScriptException e) {
System.out.println("计算失败:" + e.getMessage());
}
}
}
不同JDK版本的适配方案
由于JDK版本不同内置的JavaScript引擎有差异,我们需要根据实际使用的JDK版本选择合适的实现方案:
| JDK版本 | 可用引擎 | 实现方式 |
|---|---|---|
| JDK 1.6 - JDK 1.7 | Rhino | 直接使用ScriptEngineManager获取"JavaScript"引擎即可 |
| JDK 1.8 | Nashorn | 可以获取"JavaScript"或者"nashorn"引擎,性能更优 |
| JDK 9及以上(Nashorn已移除) | GraalVM JavaScript | 需要手动引入GraalVM JavaScript依赖,再通过ScriptEngineManager获取引擎 |
JDK 15+引入GraalVM引擎示例
如果使用的是JDK 15及以上版本,需要先在项目中引入GraalVM JavaScript的依赖,以Maven项目为例,添加以下依赖:
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>22.3.0</version>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>22.3.0</version>
</dependency>
引入依赖后,代码实现和之前的逻辑基本一致,引擎管理器会自动识别到GraalVM的JavaScript引擎:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class GraalVMCalculator {
public static void main(String[] args) {
ScriptEngineManager manager = new ScriptEngineManager();
// 获取GraalVM JavaScript引擎
ScriptEngine engine = manager.getEngineByName("graal.js");
String expression = "Math.pow(2, 10) + 100";
try {
Object result = engine.eval(expression);
System.out.println("计算结果:" + result);
} catch (ScriptException e) {
e.printStackTrace();
}
}
}
使用注意事项
表达式安全性问题
如果表达式字符串来自用户输入,直接执行会存在安全风险,比如用户输入java.lang.System.exit(0)这样的恶意代码,会导致程序异常退出。因此需要对用户输入的表达式做严格的校验,只允许包含数字、四则运算符号、括号、数学函数等合法内容,过滤掉所有脚本相关的关键字和调用。
异常处理
执行表达式时可能会抛出多种异常,除了ScriptException之外,还可能遇到NullPointerException等问题,建议对执行过程做完整的异常捕获,同时给表达式执行设置超时时间,避免恶意输入导致线程阻塞。
数据类型转换
引擎执行表达式返回的结果类型是Object,实际可能是Integer、Double等类型,需要根据业务需求做对应的类型转换,避免类型转换错误。
总结
借助Java的JavaScript引擎可以低成本的实现数学表达式字符串的解析和计算,无需手动编写复杂的解析逻辑。开发者需要根据自己的JDK版本选择合适的引擎,同时注意表达式的安全性校验和异常处理,确保功能稳定可靠。如果需要更高性能或者更复杂的表达式支持,也可以考虑结合其他专门的表达式解析库使用。
JavaJavaScript_engineNashorn数学表达式解析字符串计算修改时间:2026-06-17 01:06:42