Bạn có bao giờ nghĩ rằng một chương trình Java cũng có thể tự biên dịch và chạy một chương trình Java khác?
Điều này hoàn toàn khả thi bằng cách sử dụng Runtime.exec(String cmd) để gửi lệnh trực tiếp đến hệ điều hành, qua đó thực hiện việc biên dịch và chạy chương trình mong muốn.

Biên dịch và chạy chương trình Java từ một chương trình khác
Hãy cùng viết một chương trình Java đơn giản, chương trình này sẽ được compile và run từ một chương trình Java khác.
package com.journaldev.files;
public class Test {
public static void main(String[] args) {
System.out.println("Start");
for(String str : args){
System.out.println(str);
}
}
}
Dưới đây là chương trình khác, trong đó tôi biên dịch và chạy class Test.
package com.journaldev.files;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class CompileRunJavaProgram {
public static void main(String[] args) {
try {
runProcess("pwd");
System.out.println("**********");
runProcess("javac -cp src src/com/journaldev/files/Test.java");
System.out.println("**********");
runProcess("java -cp src com/journaldev/files/Test Hi Pankaj");
} catch (Exception e) {
e.printStackTrace();
}
}
private static void printLines(String cmd, InputStream ins) throws Exception {
String line = null;
BufferedReader in = new BufferedReader(
new InputStreamReader(ins));
while ((line = in.readLine()) != null) {
System.out.println(cmd + " " + 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());
}
}
Chú ý sự khác nhau giữa lệnh javacvà java. Chúng ta cần làm như vậy vì working directory của Eclipse là thư mục gốc của project, trong khi thư mục chứa mã nguồn các class của tôi là src. Khi tôi chạy chương trình trên từ Eclipse, đây là kết quả đầu ra:
pwd stdout: /Users/pankaj/Documents/eclipse-workspace/JavaExceptions
pwd exitValue() 0
**********
Path Serapartor = /
javac -cp src src/com/journaldev/files/Test.java exitValue() 0
**********
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Start
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Hi
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Pankaj
java -cp src com/journaldev/files/Test Hi Pankaj exitValue() 0

Đây là kết quả đầu ra khi tôi chạy cùng chương trình từ command line, với working directory là thư mục gốc của project.
pankaj:~ pankaj$ cd /Users/pankaj/Documents/eclipse-workspace/JavaExceptions
pankaj:JavaExceptions pankaj$ javac -cp src src/com/journaldev/files/Test.java
pankaj:JavaExceptions pankaj$ javac -cp src src/com/journaldev/files/CompileRunJavaProgram.java
pankaj:JavaExceptions pankaj$ java -cp src com/journaldev/files/CompileRunJavaProgram
pwd stdout: /Users/pankaj/Documents/eclipse-workspace/JavaExceptions
pwd exitValue() 0
**********
javac -cp src src/com/journaldev/files/Test.java exitValue() 0
**********
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Start
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Hi
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Pankaj
java -cp src com/journaldev/files/Test Hi Pankaj exitValue() 0
pankaj:JavaExceptions pankaj$

Chương trình trên sẽ chạy tốt trên các hệ thống Unix, nhưng sẽ không hoạt động trên Windows vì file separator trên Windows khác với Unix. Để đảm bảo chương trình độc lập nền tảng, chúng ta có thể truyền các lệnh dưới dạng argument cho hàm main. Hàm main sẽ trông như sau:
public static void main(String[] args) {
try {
if(args.length < 2) throw new Exception("Mandatory Arguments missing");
runProcess(args[0]);
runProcess(args[1]);
} catch (Exception e) {
e.printStackTrace();
}
}
Chúng ta cũng có thể dùng File.separator để tạo lệnh theo cách độc lập nền tảng. Ngoài ra, có thể lấy giá trị này từ phương thức System.getProperty, ví dụ: System.getProperty("file.separator"). Chương trình trên có thể được chỉnh sửa như sau để trở thành mã độc lập hệ thống.
String separator = File.separator;
System.out.println("File Serapartor = "+separator);
separator = System.getProperty("file.separator");
System.out.println("File Serapartor = "+separator);
runProcess("javac -cp src src"+separator+"com"+separator+"journaldev"+separator+"files"+separator+"Test.java");
System.out.println("**********");
runProcess("java -cp src com"+separator+"journaldev"+separator+"files"+separator+"Test Hi Pankaj");
Bạn sẽ nhận được kết quả giống như trên. Đó là tất cả về cách sử dụng Runtime.exec để compile và run một chương trình Java từ một chương trình Java khác. Các phương thức printLines() và runProcess() được lấy từ bài viết này.