Java の標準入力で、最後に立ち止まってしまうあなたに


Java で標準入力の内容をループで雑に取り込もうとすると、書き方によってはなぜか最後に入力待ち状態で止まってしまうことがあります。

あれ、なんでなんだろう。

と、少し気になり BufferedReader を使ったときの止まるパターン、止まらないパターンを雑に調べてみました。

後記

記事投稿後にコメント欄に戴いた情報によると、これらの動作は Eclipse がもつコンソール・ドライバや OS に依存しているのでは、とのこと。

実はかなりのレアケースかもしれないので、ふーん、程度の心構えで捉えていただけると幸いです。

環境

  • Java SE 8
    • JDK 1.8.0_91
  • Eclipse 4.6.0 (Neon)
  • Windows 7

参考サイト

サンプルデータ

最後に空行なし

1 行目
2 行目
3 行目

最後に空行あり

1 行目
2 行目
3 行目

止まる例

データの続きがあるかを気にせず、一旦標準入力の内容を取り込む。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
        String line;

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

}

「最後に空行なし」を流し込んだ場合

  • 2 行目までを出力する
  • 入力待ち状態になって止まる
    • Eclipse のコンソール上で Ctrl + z を使って入力終了を伝えても処理が進行しない

「最後に空行あり」を流し込んだ場合

  • 3 行目までを出力する
  • 入力待ち状態になって止まる
    • コンソール上で入力終了を伝えると、最後まで処理をおこなう

条件付きで止まらない例

BufferReader#ready で続きがあることを明示的に確認する。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));

        while (buffer.ready()) {
            String line = buffer.readLine();
            System.out.println(line);
        }
    }

}

「最後に空行なし」を流し込んだ場合

  • 2 行目までを出力する
  • 入力待ち状態になって止まる
    • コンソール上で入力終了を伝えると、最後まで処理をおこなう

「最後に空行あり」を流し込んだ場合

  • 3 行目までを出力する
  • 入力待ち状態にならずに正常に最後まで処理をおこなう

結論

  • 流し込むデータは最後に空行をつける
  • BufferedReader#readLine で標準入力を扱う場合、値を取り出すより前に #ready で続きのデータがあるかを確認した方がよい
    • 冷静に仕様を考えれば当たり前…
  • そもそも、雑に取り込みたいのなら #readLine は使わない方がいいのかも?