Java 与 JavaScript 的交互
Java 执行 JavaScript 的本质是:Java 代码创建并控制一个 JavaScript 执行引擎(也称为 ScriptEngine),然后将 JavaScript 代码交给这个引擎去执行,最后引擎可以将执行结果返回给 Java 代码。

使用 Java 内置的 Nashorn (Java 8+ 推荐)
从 Java 8 开始,Oracle 引入了 Nashorn,这是一个更现代、更快的 JavaScript 引擎,它完全实现了 ECMAScript 5.1 规范,并支持部分 ES6 特性,在 Java 11 中,Nashorn 被标记为“废弃”,但在 Java 8 中它仍然是官方支持的、性能最好的选择。
Nashorn 的基本使用
Nashorn 实现了 JSR-223 (Scripting for the Java Platform) 标准,因此你可以使用标准的 javax.script API 来调用它。
示例代码:
import javax.script.*;
public class NashornExample {
public static void main(String[] args) throws ScriptException {
// 1. 获取 Nashorn 脚本引擎
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
// 2. 执行简单的 JavaScript 代码
engine.eval("var msg = 'Hello from Nashorn!';");
// 3. 执行并打印结果
engine.eval("print(msg);"); // 输出: Hello from Nashorn!
// 4. 执行更复杂的代码
engine.eval("function add(a, b) { return a + b; }");
// 5. 将 Java 变量传递给 JavaScript
int a = 10;
int b = 20;
engine.eval("var sum = add(" + a + ", " + b + ");");
// 6. 将 JavaScript 变量获取到 Java 中
Object result = engine.eval("sum;");
System.out.println("The sum is: " + result); // 输出: The sum is: 30
}
}
Java 与 Nashorn 的深度交互
Nashorn 最强大的功能是 Java 和 JavaScript 之间的无缝互操作。

示例:在 JavaScript 中调用 Java 方法
import javax.script.*;
import java.util.*;
public class NashornJavaInterop {
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
// 1. 让 Nashorn 可以使用 Java 的类
engine.eval("var ArrayList = Java.type('java.util.ArrayList');");
engine.eval("var list = new ArrayList();");
// 2. 在 JavaScript 中调用 Java 对象的方法
engine.eval("list.add('Item 1');");
engine.eval("list.add(2);"); // JavaScript 的数字会自动转为 Java 的 Integer
engine.eval("list.add(new java.util.Date());");
// 3. 从 Java 访问 JavaScript 创建的对象
@SuppressWarnings("unchecked")
List<Object> myList = (List<Object>) engine.get("list");
System.out.println("Java sees the list as: " + myList);
// 输出: Java sees the list as: [Item 1, 2, Tue Oct 26 10:30:00 CST 2025]
// 4. 在 JavaScript 中调用 Java 的静态方法
engine.eval("var System = Java.type('java.lang.System');");
engine.eval("System.out.println('Printing from JS via Java System!');");
}
}
使用 Java 11+ 的 GraalVM (现代推荐)
从 Java 11 开始,Oracle 官方不再内置 Nashorn,未来的趋势是使用 GraalVM,GraalVM 是一个高性能的多语言虚拟机,它提供了一个新的 JavaScript 引擎 Graal.js,性能远超 Nashorn,并且支持更多现代 JavaScript 特性。
如何使用 GraalVM
要使用 Graal.js,你需要将相关的依赖项添加到你的项目中。
Maven 依赖:

<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>23.1.0</version> <!-- 请使用最新的版本 -->
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>23.1.0</version>
</dependency>
Gradle 依赖:
implementation 'org.graalvm.js:js:23.1.0' implementation 'org.graalvm.js:js-scriptengine:23.1.0'
GraalVM 的基本使用
GraalVM 也完全兼容 JSR-223,API 基本上和 Nashorn 一样。
示例代码:
import javax.script.*;
import org.graalvm.js.scriptengine.GraalJSScriptEngine;
public class GraalVMExample {
public static void main(String[] args) throws ScriptException {
// 1. 获取 Graal.js 脚本引擎
ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
// 2. 执行代码
engine.eval("console.log('Hello from GraalVM!');");
// 3. 定义函数并调用
engine.eval("function greet(name) { return 'Hello, ' + name + '!'; }");
Object result = engine.eval("greet('GraalVM User');");
System.out.println(result); // 输出: Hello, GraalVM User!
}
}
GraalVM 同样支持 Java 和 JavaScript 之间的深度互操作,语法与 Nashorn 类似,但更加强大和灵活。
使用第三方库 (Rhino)
Rhino 是 Mozilla 开源的 JavaScript 引擎,在 Nashorn 出现之前,Rhino 是 Java 世界中执行 JavaScript 的标准,它仍然被广泛使用,尤其是在需要兼容旧版 Java (Java 6, 7) 的项目中。
Rhino 的基本使用
Rhino 也有自己的 API,不完全兼容 JSR-223,所以用法略有不同。
Maven 依赖:
<dependency>
<groupId>org.mozilla</groupId>
<artifactId>rhino</artifactId>
<version>1.7.14</version>
</dependency>
示例代码:
import org.mozilla.javascript.*;
public class RhinoExample {
public static void main(String[] args) {
// 1. 创建一个上下文
Context cx = Context.enter();
try {
// 2. 初始化作用域
Scriptable scope = cx.initStandardObjects();
// 3. 执行字符串形式的 JavaScript 代码
cx.evaluateString(scope, "var msg = 'Hello from Rhino!';", "script", 1, null);
cx.evaluateString(scope, "print(msg);", "script", 1, null);
// 4. 执行文件中的 JavaScript 代码 (需要 Rhino 1.6R+)
// cx.evaluateReader(scope, new FileReader("path/to/your/script.js"), "script.js", 1, null);
// 5. 调用 JavaScript 函数并获取结果
Object result = cx.evaluateString(scope, "function add(a, b) { return a + b; } add(5, 7);", "script", 1, null);
// Rhino 的结果需要转换为 Java 类型
if (result instanceof Number) {
int sum = ((Number) result).intValue();
System.out.println("The sum is: " + sum); // 输出: The sum is: 12
}
} finally {
// 6. 退出上下文
Context.exit();
}
}
}
通过 Process 执行 Node.js (不推荐用于简单场景)
如果你的项目环境已经安装了 Node.js,你也可以通过 Java 的 ProcessBuilder 来启动一个 Node.js 进程,让它执行你的 JavaScript 文件,然后通过标准输入输出进行通信。
缺点:
- 性能差: 每次执行都要创建一个新的进程,开销巨大。
- 复杂: 需要处理进程间通信、数据序列化/反序列化。
- 依赖: 需要目标环境安装 Node.js。
适用场景:
- 当你需要执行的 JavaScript 代码非常复杂,依赖于 Node.js 特有的生态系统(如 NPM 包)时。
- 你无法在 Java 项目中添加 JavaScript 引擎依赖。
总结与选择建议
| 方案 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
| Nashorn | - Java 8 内置,无需额外依赖 - 性能较好 - 完全支持 JSR-223 标准 |
- Java 11+ 已废弃 - ECMAScript 版本较老 (ES5.1) |
仍在使用 Java 8 的项目,这是最简单、最快捷的方案。 |
| GraalVM | - 性能极高,远超 Nashorn - 支持现代 JavaScript (ES6+) - 是 Java 的未来方向 - 支持多种语言互操作 |
- 需要手动添加依赖 | 新项目,或需要高性能、现代 JS 特性的项目,这是长期来看的最佳选择。 |
| Rhino | - 历史悠久,非常稳定 - 兼容旧版 Java (Java 6, 7) |
- 性能不如 Nashorn 和 GraalVM - API 较旧,不完全兼容 JSR-223 |
维护旧版 Java 项目的遗留代码。 |
| Node.js 进程 | - 可利用整个 Node.js 生态系统 - 极其灵活 |
- 性能开销大 - 实现复杂,需要处理进程通信 - 依赖外部环境 |
当 JavaScript 代码严重依赖 Node.js 特定库,且无法移植到 Java 引擎时。 |
最终建议
- 如果你使用 Java 8:直接使用 Nashorn,它开箱即用,足够强大。
- 如果你使用 Java 11 或更高版本:强烈推荐使用 GraalVM,请务必添加相应的 Maven/Gradle 依赖,这是目前最先进、性能最好的方案。
- 如果你在维护一个非常老的 Java 项目:你可能别无选择,只能使用 Rhino。
- 尽量避免使用“通过 Node.js 进程执行” 的方案,除非你有非常特殊的、无法绕过的需求。
