【项目开发】Java调用Python方法
在这个人工智能技术迅速发展的时代,对于我们学生而言,参加软件竞赛已不再是单纯的技术比拼。传统的纯Java编写项目,虽然有其稳定与高效的优势,但在面对日益复杂的算法需求时,其竞争力已逐渐减弱。因此,将Java与Python这两种编程语言的优势相结合,实现算法与软件的完美融合,已成为提升项目竞争力的关键。本文将详细讲解使用Java调用Python的三大方法,并分析各个方法的优势。直接在Java程序中执
前言
在这个人工智能技术迅速发展的时代,对于我们学生而言,参加软件竞赛已不再是单纯的技术比拼。传统的纯Java编写项目,虽然有其稳定与高效的优势,但在面对日益复杂的算法需求时,其竞争力已逐渐减弱。因此,将Java与Python这两种编程语言的优势相结合,实现算法与软件的完美融合,已成为提升项目竞争力的关键。
本文将详细讲解使用Java调用Python的三大方法,并分析各个方法的优势。
1.jython库(不推荐)
首先在pom.xml中导入jython对应依赖
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<!--指定Python的版本-->
<version>2.7.0</version>
</dependency>
1.1.手动编写Python语句
这里我们编写一个简单的a + b函数的实现样例。
public static void main(String[] args) {
// 创建Python解释器
PythonInterpreter interpreter = new PythonInterpreter();
// 编写函数
interpreter.exec("def add(a, b):\n return a + b\n");
// 传入参数
int a = 5;
int b = 10;
// 调用 Python 函数
PyObject eval = interpreter.eval("add(" + a + ", " + b + ")");
// 获取结果并打印
int result = Py.tojava(eval, int.class);
System.out.println("Result: " + result);
}
这样就可以得到返回结果
Result: 15
1.2.读取Python文件进行调用
编写一个jythonTest.py文件
def add(a, b):
return a + b
使用PythonInterpreter.execfile方法调用py文件
public static void main(String[] args) {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile("D:\\Workspaces\\Project\\intelpython\\jythonTest.py");
// 调用jythonTest.py中的add方法
PyFunction func = interpreter.get("add",PyFunction.class);
Integer a = 5;
Integer b = 10;
PyObject pyobj = func.__call__(new PyInteger(a), new PyInteger(b));
System.out.println("获得方法的返回值 = " + pyobj.toString());
}
总结:
上述两个方法的优点是其集成性,Jython允许你在Java中直接执行Python代码,使得Java和Python代码可以直接进行交互。
缺点也是明显的,首先,Jython说到底是Java的库,可能无法完全支持Python的所有库和功能,其次,Python工程师的工作高度耦合在Java代码中,如果你和你的Python同事不能够忍受这种开发方式,那么就不要用这种方法。
2.Java调用命令行(推荐)
这种方法的原理是通过Java代码调用操作系统的命令行接口,然后在命令行中执行Python脚本。
Java程序可以通过Runtime.getRuntime().exec()
方法或者更高级的ProcessBuilder
类来实现这一功能。执行Python脚本后,Java程序可以通过InputStream
流来捕获并处理Python脚本的输出结果。
2.1.Runtime.getRuntime().exec()方法调用
- 首先需要编写执行Python脚本的命令行语句
// 编写要执行的命令,注意路径中的转义字符
String command = "python D:\\demo1.py agrs1";
- 使用Runtime.getRuntime().exec()方法执行命令
// 执行命令
Process process = Runtime.getRuntime().exec(command);
- 使用process.getInputStream()捕获InputStream流,从而获取执行结果
// 读取标准输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 关闭读取器
reader.close();
- 使用process.getErrorStream()捕获标准错误流(可选),如果Python语句报错会打印报错信息
// 读取标准错误输出(可选)
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((line = errorReader.readLine()) != null) {
System.err.println(line);
}
// 关闭错误读取器
errorReader.close();
- 等待进程结束 ,使用process.waitFor()方法获取返回码
// 等待进程结束
int exitCode = process.waitFor();
System.out.println("返回码: " + exitCode);
完整代码为:
public static void main(String[] args) {
try {
// 编写要执行的命令,注意路径中的转义字符
String command = "python D:\\demo1.py agrs1";
// 执行命令
Process process = Runtime.getRuntime().exec(command);
// 读取标准输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 关闭读取器
reader.close();
// 读取标准错误输出(可选)
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((line = errorReader.readLine()) != null) {
System.err.println(line);
}
// 关闭错误读取器
errorReader.close();
// 等待进程结束
int exitCode = process.waitFor();
System.out.println("Python script exited with code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
2.2.ProcessBuilder类调用(最推荐)
- 编写命令
// 配置Python脚本的路径和要传递的参数
String pythonScriptPath = "/path/to/your/python/script.py";
String[] command = {"python", pythonScriptPath, "arg1", "arg2"}; // 根据需要调整命令和参数
- 使用ProcessBuilder启动进程
// 使用ProcessBuilder启动进程
ProcessBuilder pb = new ProcessBuilder(command);
Process process = pb.start();
完整代码:
public class JavaCallPython {
public static void main(String[] args) {
try {
// 配置Python脚本的路径和要传递的参数
String pythonScriptPath = "/path/to/your/python/script.py";
String[] command = {"python", pythonScriptPath, "arg1", "arg2"}; // 根据需要调整命令和参数
// 使用ProcessBuilder启动进程
ProcessBuilder pb = new ProcessBuilder(command);
Process process = pb.start();
// 读取标准输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 读取标准错误输出(可选)
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((line = errorReader.readLine()) != null) {
System.err.println(line);
}
// 关闭读取器
reader.close();
errorReader.close();
// 等待进程结束并获取退出值
int exitCode = process.waitFor();
System.out.println("\nExited with error code : " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}
总结:
两种方法都是通过创建一个Process进程调用命令行获取Python脚本的执行结果。主要区别为第二种方法需要额外创建一个ProcessBuilder类,ProcessBuilder类接收的是String数组,相较于Runtime只接收一个String字符串,ProcessBuilder类编写命令更加灵活。
3.调用云端模型(最推荐)
这种方法需要Python工程师在百度云、腾讯云等云平台上开启接口,然后通过Hutool的工具类发送HTTP请求调用云端接口。
首先需要导入Hutool库
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.17</version>
</dependency>
- 填写接口地址,使用Map作为表单数据(一般使用表单,比较灵活,文件和文本都可以传输)
String url = "https://xxx.com/";
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("student", student);
paramMap.put("answer", answer);
- 使用HttpRequest发送请求
HttpResponse execute = HttpRequest.post(url)
.header(AUTH_REQUEST_HEADER, AUTH_REQUEST_SECRET)
.form(paramMap)
.execute();
- 判断返回结果合法性,进行相关处理
// 判断返回结果是否为空
if (ObjectUtil.isNull(execute)) {
throw new RuntimeException("调用结果为空");
}
// 判断接口是否调用成功
int status = execute.getStatus();
if (status != 200) {
throw new RuntimeException("执行失败,错误码:" + status);
}
- 获取返回结果
// 打印响应结果
System.out.println(execute.body());
完整代码:
// 利用hutool工具的HttpRequest类发送请求调用python接口
String url = "";
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("student", student);
paramMap.put("answer", answer);
HttpResponse execute = HttpRequest.post(url)
.header(AUTH_REQUEST_HEADER, AUTH_REQUEST_SECRET)
.form(paramMap)
.execute();
// 判断返回结果是否为空
if (ObjectUtil.isNull(execute)) {
throw new RuntimeException("调用结果为空");
}
// 判断接口是否调用成功
int status = execute.getStatus();
if (status != 200) {
return Result.fail("执行失败,错误码:" + status);
}
// 打印响应结果
System.out.println(execute.body());
4.总结
jython库
优点:
- 直接在Java程序中执行,可以直接利用Java虚拟机(JVM)的性能优势,减少进程间通信的开销。
缺点:
- Jython可能无法完全支持Python的所有库和功能。
Java调用命令行
优点:
- Java和Python进程是独立的,这使得它们可以更容易地并行运行,而不会影响彼此的性能。
- 对于对硬件要求比较高的Python模型, 本地部署可能存在一定的困难。
- 对于开发人员比较友好,两者的开发工作分离。
缺点:
- 进程间通讯可能会引入额外的开销和复杂性。
调用云端模型
优点:
- 对于开发人员比较友好,两者的开发工作分离。
- 利于构建大型算法模型,如百度云等云端平台对于Python模型支持度很高,比起本地更容易部署。
缺点:
- 需要Java和Python工程师对HTTP请求有一定了解。
- 云端接口需要支付一定的费用。
更多推荐
所有评论(0)