【项目开发】Java调用Python方法

前言

在这个人工智能技术迅速发展的时代,对于我们学生而言,参加软件竞赛已不再是单纯的技术比拼。传统的纯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()方法调用

  1. 首先需要编写执行Python脚本的命令行语句
// 编写要执行的命令,注意路径中的转义字符
String command = "python D:\\demo1.py agrs1";
  1. 使用Runtime.getRuntime().exec()方法执行命令
// 执行命令  
Process process = Runtime.getRuntime().exec(command);
  1. 使用process.getInputStream()捕获InputStream流,从而获取执行结果
// 读取标准输出  
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
	System.out.println(line);
}
// 关闭读取器  
reader.close();
  1. 使用process.getErrorStream()捕获标准错误流(可选),如果Python语句报错会打印报错信息
// 读取标准错误输出(可选)  
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((line = errorReader.readLine()) != null) {
	System.err.println(line);
}
// 关闭错误读取器  
errorReader.close();
  1. 等待进程结束 ,使用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类调用(最推荐)

  1. 编写命令
// 配置Python脚本的路径和要传递的参数  
String pythonScriptPath = "/path/to/your/python/script.py";  
String[] command = {"python", pythonScriptPath, "arg1", "arg2"}; // 根据需要调整命令和参数  
  1. 使用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>
  1. 填写接口地址,使用Map作为表单数据(一般使用表单,比较灵活,文件和文本都可以传输)
String url = "https://xxx.com/";
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("student", student);
paramMap.put("answer", answer);
  1. 使用HttpRequest发送请求
HttpResponse execute = HttpRequest.post(url)
    .header(AUTH_REQUEST_HEADER, AUTH_REQUEST_SECRET)
    .form(paramMap)
    .execute();
  1. 判断返回结果合法性,进行相关处理
// 判断返回结果是否为空
if (ObjectUtil.isNull(execute)) {
    throw new RuntimeException("调用结果为空");
}

// 判断接口是否调用成功
int status = execute.getStatus();
if (status != 200) {
    throw new RuntimeException("执行失败,错误码:" + status);
}
  1. 获取返回结果
// 打印响应结果
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请求有一定了解。
  • 云端接口需要支付一定的费用。
  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaPython混合开发是一种将JavaPython两种编程语言结合使用的开发方法。它的目的是通过充分发挥两种语言的优势,来满足不同开发需求。 Java是一种面向对象的编程语言,它具有强大的跨平台性和丰富的类库支持。它可以用于开发大型企业应用、Web应用和移动应用等。而Python是一种简单易学的脚本语言,它具有清晰简洁的语法和强大的开发效率,被广泛应用于数据分析、人工智能、科学计算和Web开发等领域。 将JavaPython混合开发可以发挥两者的优势,提高开发效率和灵活性。比如,可以使用Java开发底层的系统模块和高性能的算法,然后使用Python来编写测试脚本和数据分析脚本,以提高开发效率和减少开发周期。此外,JavaPython还可以通过调用对方的代码来实现相互调用和集成,使得应用具有更高的灵活性和可扩展性。 JavaPython混合开发还可以利用各自的生态系统。Java拥有丰富的类库和框架,可以提供强大的功能和稳定性;而Python具有丰富的第三方库,例如NumPy、Pandas和TensorFlow等,可以提供丰富的数据分析和机器学习功能。开发者可以根据需求选择最适合的工具和环境,从而更加高效地完成任务。 总而言之,JavaPython混合开发可以充分发挥两者的优势,提高开发效率和灵活性,同时利用各自的生态系统,满足不同的开发需求。这种混合开发的方式在实际项目中被广泛应用,并取得了良好的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值