核心思想
无论哪种方法,其核心思想都是 “进程间通信”(Inter-Process Communication, IPC),Java 程序会启动一个独立的 Python 进程,然后将数据传递给这个进程,Python 执行完代码后,再将结果返回给 Java 程序,它们之间需要一个“桥梁”来传递数据,这个桥梁通常是:

- 标准输入/输出流:Java 向 Python 进程的标准输入写入数据,Python 从标准输入读取数据,执行后将结果写入标准输出,Java 再从标准输出读取。
- 网络套接字:Java 启动一个 Python HTTP 服务器,通过网络 API(如 RESTful API)进行调用。
- 共享内存:更高级的技术,性能更高,但实现复杂。
使用 ProcessBuilder (最直接、最常用)
这是 Java 内置的功能,无需任何第三方库,通过启动一个子进程来执行 Python 脚本,它通过标准输入输出来进行数据交换。
适用场景
- 简单的脚本调用。
- 不想引入额外依赖的 Java 项目。
- 对性能要求不高。
优点
- 纯 Java 实现:无需额外库。
- 灵活性高:可以传递命令行参数,并自由控制进程。
缺点
- 代码相对繁琐:需要手动处理输入输出流。
- 性能开销大:每次调用都需要创建一个新进程。
- 错误处理复杂:需要捕获
IOException,并正确关闭资源,否则可能导致进程挂起或资源泄露。 - 数据格式受限:通常需要将 Java 对象序列化为字符串(如 JSON)进行传递,Python 端再反序列化。
详细步骤和代码示例
准备 Python 脚本
创建一个名为 script.py 的文件,它可以接收字符串参数,处理并返回结果。
# script.py
import sys
import json
# 从标准输入读取一行数据
input_data = sys.stdin.readline()
try:
# 将 JSON 字符串解析为 Python 字典
data = json.loads(input_data)
name = data.get('name', 'Guest')
age = data.get('age', 0)
# 处理数据
result_message = f"Hello, {name}! You are {age} years old. In 5 years, you will be {age + 5}."
# 将结果打包成 JSON 字符串,写入标准输出
# 注意:print 默认会换行,json.dumps 可以确保格式正确
print(json.dumps({"status": "success", "message": result_message}))
except json.JSONDecodeError:
print(json.dumps({"status": "error", "message": "Invalid JSON format"}))
except Exception as e:
print(json.dumps({"status": "error", "message": str(e)}))
编写 Java 代码

在 Java 中,我们使用 ProcessBuilder 来启动 python 命令,并与之交互。
import java.io.*;
public class PythonCaller {
public static void main(String[] args) {
// 准备传递给 Python 脚本的数据
String jsonData = "{\"name\": \"Alice\", \"age\": 30}";
try {
// 1. 创建 ProcessBuilder
// 注意:如果你的 Python 不在系统 PATH 中,需要提供完整路径,"C:\\Python39\\python.exe"
ProcessBuilder pb = new ProcessBuilder("python", "script.py");
// 2. 启动进程
Process process = pb.start();
// 3. 获取进程的输入流和输出流
// Java 的 OutputStream 写入到 Python 的 InputStream
OutputStream os = process.getOutputStream();
// Python 的 OutputStream 写入到 Java 的 InputStream
InputStream is = process.getInputStream();
// 获取 Python 的错误流,方便调试
InputStream errorStream = process.getErrorStream();
// 4. 向 Python 脚本发送数据
os.write(jsonData.getBytes());
os.flush(); // 确保数据被发送
os.close(); // 关闭流,告诉 Python 没有更多数据了
// 5. 读取 Python 脚本的返回结果
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
// 6. 等待 Python 进程执行完毕
int exitCode = process.waitFor();
// 7. 处理结果
if (exitCode == 0) {
System.out.println("Python script executed successfully.");
System.out.println("Response from Python: " + response.toString());
} else {
// 读取错误流
BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream));
String errorLine;
StringBuilder errorResponse = new StringBuilder();
while ((errorLine = errorReader.readLine()) != null) {
errorResponse.append(errorLine);
}
System.err.println("Python script failed with exit code: " + exitCode);
System.err.println("Error from Python: " + errorResponse.toString());
}
// 8. 关闭所有资源
reader.close();
is.close();
errorStream.close();
} catch (IOException e) {
System.err.println("Error starting or communicating with Python process: " + e.getMessage());
} catch (InterruptedException e) {
System.err.println("The process was interrupted: " + e.getMessage());
Thread.currentThread().interrupt(); // 恢复中断状态
}
}
}
如何运行:
- 将
script.py和PythonCaller.java放在同一个目录下。 - 确保 Python 已安装并配置好环境变量。
- 编译并运行 Java 程序:
javac PythonCaller.java java PythonCaller
预期输出:
Python script executed successfully.
Response from Python: {"status": "success", "message": "Hello, Alice! You are 30 years old. In 5 years, you will be 35."}
使用第三方库 (更简洁、更强大)
手动管理 ProcessBuilder 很繁琐,一些优秀的第三方库封装了这些细节,提供了更简洁、更强大的 API。

推荐库:Junrar (不,这是个解压库,抱歉) -> Py4J 或 Java-Python Bridge
这里重点介绍 Py4J,它是一个非常流行和强大的库。
Py4J 的工作原理:
- Java 端启动一个网关,这个网关监听一个端口。
- Python 端通过 Py4J 库连接到这个 Java 网关。
- Python 端可以调用 Java 对象的方法,甚至可以创建新的 Java 对象。
- 反之,Java 端也可以通过 Py4J 的
GatewayServer调用 Python 端注册的函数或对象。
它比 ProcessBuilder 更高效,因为它可以保持长连接,并且数据交换是类型安全的。
使用 Py4J 的步骤
准备 Python 脚本 (py4j_example.py)
# py4j_example.py
from py4j.java_gateway import JavaGateway, GatewayServer
# 1. 定义一个 Python 类,它的方法可以被 Java 调用
class PythonService:
def greet(self, name):
print(f"Python received name: {name}")
return f"Hello from Python, {name}!"
def calculate_average(self, numbers_list):
if not numbers_list:
return 0
return sum(numbers_list) / len(numbers_list)
# 2. 创建 PythonService 实例
python_service = PythonService()
# 3. 启动 GatewayServer,将 Python 服务暴露给 Java
# 注意:默认端口是 25333
gateway = GatewayServer(python_service)
gateway.start()
print("Gateway Server Started")
编写 Java 代码 (需要添加 Py4J 依赖)
将 Py4J 的 JAR 包添加到你的项目中,如果你使用 Maven,在 pom.xml 中添加:
<dependency>
<groupId>net.sf.py4j</groupId>
<artifactId>py4j</artifactId>
<version>0.10.9.7</version> <!-- 请使用最新版本 -->
</dependency>
编写 Java 代码:
import net.sf.py4j.GatewayServer;
import java.util.Arrays;
import java.util.List;
public class Py4JEntryPoint {
// 这个方法必须是 public static 的
public static PythonService getPythonService() {
// 这里返回一个代理对象,Py4J 会用它来连接 Python
// 实际的 PythonService 对 