Difference between ProcessBuilder and Runtime.exec() Difference between ProcessBuilder and Runtime.exec() java java

Difference between ProcessBuilder and Runtime.exec()


The various overloads of Runtime.getRuntime().exec(...) take either an array of strings or a single string. The single-string overloads of exec() will tokenise the string into an array of arguments, before passing the string array onto one of the exec() overloads that takes a string array. The ProcessBuilder constructors, on the other hand, only take a varargs array of strings or a List of strings, where each string in the array or list is assumed to be an individual argument. Either way, the arguments obtained are then joined up into a string that is passed to the OS to execute.

So, for example, on Windows,

Runtime.getRuntime().exec("C:\DoStuff.exe -arg1 -arg2");

will run a DoStuff.exe program with the two given arguments. In this case, the command-line gets tokenised and put back together. However,

ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");

will fail, unless there happens to be a program whose name is DoStuff.exe -arg1 -arg2 in C:\. This is because there's no tokenisation: the command to run is assumed to have already been tokenised. Instead, you should use

ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe", "-arg1", "-arg2");

or alternatively

List<String> params = java.util.Arrays.asList("C:\DoStuff.exe", "-arg1", "-arg2");ProcessBuilder b = new ProcessBuilder(params);


Look at how Runtime.getRuntime().exec() passes the String command to the ProcessBuilder. It uses a tokenizer and explodes the command into individual tokens, then invokes exec(String[] cmdarray, ......) which constructs a ProcessBuilder.

If you construct the ProcessBuilder with an array of strings instead of a single one, you'll get to the same result.

The ProcessBuilder constructor takes a String... vararg, so passing the whole command as a single String has the same effect as invoking that command in quotes in a terminal:

shell$ "command with args"


There are no difference between ProcessBuilder.start() and Runtime.exec() because implementation of Runtime.exec() is:

public Process exec(String command) throws IOException {    return exec(command, null, null);}public Process exec(String command, String[] envp, File dir)    throws IOException {    if (command.length() == 0)        throw new IllegalArgumentException("Empty command");    StringTokenizer st = new StringTokenizer(command);    String[] cmdarray = new String[st.countTokens()];    for (int i = 0; st.hasMoreTokens(); i++)        cmdarray[i] = st.nextToken();    return exec(cmdarray, envp, dir);}public Process exec(String[] cmdarray, String[] envp, File dir)    throws IOException {    return new ProcessBuilder(cmdarray)        .environment(envp)        .directory(dir)        .start();}

So code:

List<String> list = new ArrayList<>();new StringTokenizer(command).asIterator().forEachRemaining(str -> list.add((String) str));new ProcessBuilder(String[])list.toArray())            .environment(envp)            .directory(dir)            .start();

should be the same as:

Runtime.exec(command)

Thanks dave_thompson_085 for comment