如何在一个Java程序中编译和运行另一个Java程序?

26

我有一个Main.java和Test.java类,我想编译并在Test.java代码中运行Main.java。这是我的代码:

    Process pro1 = Runtime.getRuntime().exec("javac Main.java");
    pro1.waitFor();
    Process pro2 = Runtime.getRuntime().exec("java Main");

    BufferedReader in = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
    String line = null;

    while ((line = in.readLine()) != null) {
        System.out.println(line);
    }

我在Main.java中只是打印了"ok",但是这段代码没有打印任何东西。问题出在哪里?


看起来你在寻找http://docs.codehaus.org/display/JANINO/Home ;)。 - phihag
1
你应该使用Process.getOutputStream,不是吗? - Sasha Goldshtein
3
对我来说运行正常。你确定java和javac在PATH环境变量中吗?如果你从命令行运行这些命令,它能否正常工作?如果你想更好地控制编译过程,你也可以使用javax.tools包进行编译。 - Sergei Tachenov
@hilal,我不认为classpath与此有任何关系。我怀疑是PATH的问题。 - Sergei Tachenov
@hilal,对不起,路径与此无关。如果其中一个命令不可用,它将会因为IOException而中断。 - Sergei Tachenov
显示剩余8条评论
4个回答

30

我已修改代码以包括一些检查:

public class Laj {

  private static void printLines(String name, InputStream ins) throws Exception {
    String line = null;
    BufferedReader in = new BufferedReader(
        new InputStreamReader(ins));
    while ((line = in.readLine()) != null) {
        System.out.println(name + " " + line);
    }
  }

  private static void runProcess(String command) throws Exception {
    Process pro = Runtime.getRuntime().exec(command);
    printLines(command + " stdout:", pro.getInputStream());
    printLines(command + " stderr:", pro.getErrorStream());
    pro.waitFor();
    System.out.println(command + " exitValue() " + pro.exitValue());
  }

  public static void main(String[] args) {
    try {
      runProcess("javac Main.java");
      runProcess("java Main");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

这是 Main.java 的代码:

public class Main {
  public static void main(String[] args) {
    System.out.println("ok");
  }
}

当一切正常时,它就能正常工作:

alqualos@ubuntu:~/tmp$ java Laj
javac Main.java exitValue() 0
java Main stdout: ok
java Main exitValue() 0

比如说,现在我在 Main.java 文件中遇到了一些错误:

alqualos@ubuntu:~/tmp$ java Laj
javac Main.java stderr: Main.java:3: package Systems does not exist
javac Main.java stderr:     Systems.out.println("ok");
javac Main.java stderr:            ^
javac Main.java stderr: 1 error
javac Main.java exitValue() 1
java Main stdout: ok
java Main exitValue() 0

它仍然打印"ok",因为先前编译的Main.class仍在那里,但至少你可以看到当你的进程正在运行时发生了什么。


+1. 我把这两个文件放在同一个包里了。这是我的错误。谢谢Sergey。 - user467871
@Addy,那么你需要在第二个进程上使用 getOutputStream() 来提供数据。或者只需关闭该流以使进程立即获得 EOF。 - Sergei Tachenov
我们怎么在这里传递参数? - Divyang Shah
当我尝试使用 && 运行这两个命令时,像这样... javac Main.java && java Main -> 它失败了... 你能帮忙吗 @sergey - cafebabe1991

0

你还需要

pro2.waitFor();

因为执行该进程需要一些时间,而且在该进程完成之前无法获取 exitValue()。


我做了这个,但是它并没有给出任何答案。 - user467871
@hilal,你需要在最后一个循环之后执行它。当进程正在运行时,你可以读取其输出,这是可以的,但只有在它完成后才能访问 exitValue()。 - Sergei Tachenov
@hilal,第一版的代码对我来说没有问题,不需要更改。但是我会发布带有检查的代码。 - Sergei Tachenov

0

我已经在Laj类的主函数中添加了条件,以检查编译过程是否成功完成。

public class Laj {

  private static void printLines(String name, InputStream ins) throws Exception {
    String line = null;
    BufferedReader in = new BufferedReader(
        new InputStreamReader(ins));
    while ((line = in.readLine()) != null) {
        System.out.println(name + " " + line);
    }
  }

  private static int runProcess(String command) throws Exception {
    Process pro = Runtime.getRuntime().exec(command);
    printLines(command + " stdout:", pro.getInputStream());
    printLines(command + " stderr:", pro.getErrorStream());
    pro.waitFor();
   // System.out.println(command + " exitValue() " + pro.exitValue());
    return pro.exitValue();
  }

  public static void main(String[] args) {
    try {
    int k =  runProcess("javac Main.java");
    if (k==0)
    k=runProcess("java Main");

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

是否可以进一步澄清一下答案? - rockinfresh

0
你可以尝试结合两个开源库:jaxecjhome(我是它们的作者)。这是如何从你的Java程序中调用另一个Java程序的方法:
import com.yegor256.Jaxec;
import com.yegor256.Jhome;

// compile it first:
new Jaxec()
  .with(new Jhome().path("bin/javac").toString())
  .with("Hello.java") // the file name
  .exec();

// next, execute it:
new Jaxec()
  .with(new Jhome().path("bin/java").toString())
  .with("Hello") // the name of the class
  .exec();

在幕后,它将找到JAVA_HOME的位置,并调用ProcessBuilder来运行两个新的进程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接