プロセスの起動

コンソール限定だけども。
後始末とか意外と知られていないようなので。

public class Main {

  public static void main(String[] args) {
    try {
      run("cmd.exe", "/c", "dir", "/s", "\\*.exe");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static class Pipe implements Runnable {

    private InputStream src;
    private OutputStream dest;

    public Pipe(InputStream src, OutputStream dest) {
      this.src = src;
      this.dest = dest;
    }

    @Override
    public void run() {
      BufferedReader reader = new BufferedReader(new InputStreamReader(src));
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest));
      String line = null;
      try {
        while ((line = reader.readLine()) != null) {
          writer.write(line);
          writer.newLine();
        }
        writer.flush();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

  }

  public static int run(String... cmd) throws Exception {
    Process process = new ProcessBuilder(cmd).start();
    // この3つのリソースは使わなくてもクローズする必要がある
    InputStream stdout = process.getInputStream();
    InputStream stderr = process.getErrorStream();
    OutputStream stdin = process.getOutputStream();
    // プロセスの標準出力・エラー出力共にバッファリングされており、ある程度溜まると書き込みがブロックされてしまうので、こっちで読み込んでやる必要がある
    // ただ、プロセスから取得したストリームはプロセスが終了するまで読み込み可能な状態にあるので、プロセスの終了を待機する前に一般的な読み込み処理のループを書いてしまうと終了条件が成立しない
    // そこで、標準出力・エラー出力からの読み込みは別スレッドで行い、メインのスレッドはプロセスの終了を待機するだけにする
    Thread outCopyThread = new Thread(new Pipe(stdout, System.out));
    Thread errCopyThread = new Thread(new Pipe(stderr, System.err));
    outCopyThread.start();
    errCopyThread.start();
    Exception e = null;
    try {
      return process.waitFor();
    } catch (Exception ex) {
      e = ex;
    } finally {
      // 個別に後始末を行い、かつエラーが起きたら最初のものをthrowする
      // もっとマシな書き方が無いものか・・・
      try {
        outCopyThread.join();
      } catch (InterruptedException ex) {
      }
      try {
        errCopyThread.join();
      } catch (InterruptedException ex) {
      }
      try {
        stdout.close();
      } catch (Exception ex) {
        if (e == null) {
          e = ex;
        } else {
          ex.printStackTrace();
        }
      }
      try {
        stderr.close();
      } catch (Exception ex) {
        if (e == null) {
          e = ex;
        } else {
          ex.printStackTrace();
        }
      }
      try {
        stdin.close();
      } catch (Exception ex) {
        if (e == null) {
          e = ex;
        } else {
          ex.printStackTrace();
        }
      }
      process.destroy();
    }
    throw e;
  }

}