JavaでC,C++のsystem("cls");と同等の機能を実装する

# はじめに #
少し前にC言語でコンソールオセロゲームを作ったので、
Javaでも作ってみようとしたところ、
Cで出来たsystem("cls");をJavaでも出来ないかと思って調べたが、
色々手こずったのでここにメモしておこうと思う。

## Sorce Code ##
```java
import java.io.IOException;

/**
 * コンソール画面の出力を制御するクラス
 */
public class ConsoleControl {
	/**
	 * コンソール画面の出力をクリアするメソッド
	 * @throws	IOException
	 * @throws 	InterruptedException
	 */
	public void clearScreen() throws IOException, InterruptedException {
        new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
    }
}
```

### ProccessBuilderクラス ###
まずは、このProccessBuilderクラスに関してだが、公式の説明を見てみると、
"Processクラスのインスタンスを構築するためのクラス"という事で、
このクラスのインスタンスを作成することで、外部コマンドを用いた新しいプロセスの実行環境を構築することができる。
Open JDK SE8で中身を見てみると、
コンストラクタの引数に指定したコマンドをProcessBuilderクラスにある
commandというList<String>型の変数に格納していた。
以下、Open JDK のソース引用

```java
    private List<String> command;
    private File directory;
    private Map<String,String> environment;
    private boolean redirectErrorStream;
    private Redirect[] redirects;

    public ProcessBuilder(String... command) {
        this.command = new ArrayList<>(command.length);
        for (String arg : command)
            this.command.add(arg);
    }
```

### inheritIOメソッド ###
このメソッドは以下のように定義されていた。(Open JDK のソース引用)

```java
    public ProcessBuilder inheritIO() {
        Arrays.fill(redirects(), Redirect.INHERIT);
        return this;
    }
```

このメソッドはArrays.fill関数を使ってINHERITフラグをredirectsに代入しているだけである。
このINHERITフラグは何を意味するのかというと、公式の説明にはこう書いてあった。
>これが、ほとんどのオペレーシング・システム・コマンド・インタプリタ(シェル)の通常の動作になります。

また、inheritIOメソッドに関する説明は
>サブプロセスの標準入出力の入力元と出力先を、現在のJavaプロセスと同じものに設定します。
これは、簡易メソッドです。次の形式の呼出しは、
pb.inheritIO()
次の呼び出しと正確に同じ動作になります。
pb.redirectInput(Redirect.INHERIT)
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT)
この動作は、ほとんどのオペレーティング・システム・コマンド・インタプリタや標準Cライブラリ関数system()と同等のものになります。

つまりは、Javaの標準入出力に、外部プログラムの入出力を統合することができるということであることが分かった。
標準入出力に関しては[ここ](https://qiita.com/angel_p_57/items/03582181e9f7a69f8168)を参照。
まぁ、公式の説明の最後に
>この動作は、ほとんどのオペレーティング・システム・コマンド・インタプリタや標準Cライブラリ関数system()と同等のものになります。

と書いているのでsystem()と同じ動作をしてくれると理解しておこう。

### startメソッド ###
ソースは長いので省略。
このメソッドで、ProcessBuilderで指定されたコマンドや実行ファイルを起動している。
メソッド名からなんとなく察せる。

### waitForメソッド ###
ソースは(ry
このメソッドは、他のスレッドで動いているサブプロセスが終わるまで今処理中のスレッドを待機させるメソッド。

#まとめ#

前回のソースを改変して、以下のようにした。

```java
import java.io.IOException;

public class ConsoleControl {
	private ProcessBuilder pb;

	/**
	 * ConsoleControlクラスのコンストラクタです。
	 * 指定したコマンドを実行する新しいプロセスを実行する環境を構築します。
	 * @param command 実行するコマンド
	 */
	public ConsoleControl(String... command) {
		pb = new ProcessBuilder(command);
	}

	/**
	 * コマンドプロンプトの画面をクリアするメソッド。
	 */
	public void cls() throws IOException, InterruptedException {
		pb.inheritIO().start().waitFor();
		/*
		 * // ProcesserBuildのコンストラクタ引数で指定した外部コマンドを
		 * // コマンドプロンプトで実行できるように変換
		 * ProcessBuilder pbInheritIO = pb.inheritIO();
		 * // 外部コマンドで実行
		 * Process pro = pbInheritIO.start();
		 * // 他のスレッドで動いているプロセスが終わるまで待機
		 * pro.waitFor();
		 */
	}
}

```
### Windowsの場合 ###
```java
var cc = new ConsoleControl("cmd", "/c", "cls");
```

### Linuxの場合 ###

```java
var cc = new ConsoleControl("/bin/bash", "-c", "clear");
```

みたいな感じかな？
おそらく、説明が不足してたり勘違いしてる可能性もあるのでご指摘いただけたら嬉しいです。

おわり。