My開発メモ

標準入力から読み取る(Java)

Javaで簡単なアプリを作ってたんだけど、標準入力から文字なり数値なりを受け取るやり方を忘れてたので、メモしておく。

Scanfを使って書いたのが、これ。

Test.jva

import java.util.Scanner;

public class Test {

  public static void main(String[] args) {
    int num = inputNum();
    String txt = inputTxt();

    System.out.println("num:" + num + " txt:" + txt);
  }

  public static int inputNum() {
    Scanner scanner = new Scanner(System.in);
    System.out.print("num > ");
    int num = scanner.nextInt();
    scanner.nextLine();  // 数字入力のあとの改行コードを吸い取る
    scanner.close();
    return num;
  }

  public static String inputTxt() {
    Scanner scanner = new Scanner(System.in);
    System.out.print("txt > ");
    String txt = scanner.nextLine();
    scanner.close();
    return txt;
  }
}

これを実行すると、以下のようになる。

$ java Test
num > 23
txt > Exception in thread "main" java.util.NoSuchElementException: No line found
	at java.base/java.util.Scanner.nextLine(Scanner.java:1651)
	at Test.inputTxt(Unknown Source)
	at Test.main(Unknown Source)

で、標準入力は1つしかないんだし、2つインスタンスを作成して、JVMも困ってしまったんだろうな。

作り直したのが、これ。

Test2.java

import java.util.Scanner;

public class Test2 {
    static Scanner scanner = null;
    
	public static void main(String[] args) {
        int num = inputNum();
        String txt = inputTxt();

		System.out.println("num:" + num + " txt:" + txt);
        scanner.close();
	}

    public static int inputNum() {
		scanner = new Scanner(System.in);
		System.out.print("num > ");
		int num = scanner.nextInt();
		scanner.nextLine();  // 数字入力のあとの改行コードを吸い取る
        return num;
    }

    public static String inputTxt() {
		scanner = new Scanner(System.in);
		System.out.print("txt > ");
		String txt = scanner.nextLine();
        return txt;
    }
}

実行結果

$ java Test2
num > 23
txt > あめま
num:23 txt:あめま

BufferedReaderInputStreamReader の場合

もうひとつの場合はどうなんだろう?

Test3.java

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

public class Test3 {

	public static void main(String[] args) {
        int num = inputNum();
        String txt = inputTxt();

		System.out.println("num:" + num + " txt:" + txt);
	}

    public static int inputNum() {
        InputStreamReader is = new InputStreamReader(System.in);
        BufferedReader stdin = new BufferedReader(is);

		System.out.print("num > ");
        int num = 0;
        try {
            String txtNum = stdin.readLine();
            num = Integer.parseInt(txtNum);
        } catch (IOException e) {
            e.printStackTrace();
        } 
        return num;
    }

    public static String inputTxt() {
        InputStreamReader is = new InputStreamReader(System.in);
        BufferedReader stdin = new BufferedReader(is);

        String txt = null;
		System.out.print("txt > ");
        try {
            txt = stdin.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return txt;
    }
}

実行例

$ java Test3
num > 34
txt > かい〜の
num:34 txt:かい〜の

これはうまくいくのである。

ただ、close処理を付け加えるとうまくいかなくなる。

Test4.java

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

public class Test4 {

	public static void main(String[] args) {
        int num = inputNum();
        String txt = inputTxt();

		System.out.println("num:" + num + " txt:" + txt);
	}

    public static int inputNum() {
        InputStreamReader is1 = new InputStreamReader(System.in);
        BufferedReader stdin1 = new BufferedReader(is1);

		System.out.print("num > ");
        int num = 0;
        try {
            String txtNum = stdin1.readLine();
            num = Integer.parseInt(txtNum);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // クローズ処理
            if (stdin1 != null) {
                try {
                    stdin1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return num;
    }

    public static String inputTxt() {
        InputStreamReader is2 = new InputStreamReader(System.in);
        BufferedReader stdin2 = new BufferedReader(is2);

        String txt = null;
		System.out.print("txt > ");
        try {
            txt = stdin2.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // クローズ処理
            if (stdin2 != null) {
                try {
                    stdin2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return txt;
    }
}

実行例

$ java Test4
num > 56
txt > java.io.IOException: Stream closed
	at java.base/java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:176)
	at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:342)
	at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
	at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
	at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
	at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
	at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
	at Test4.inputTxt(Unknown Source)
	at Test4.main(Unknown Source)
num:56 txt:null

やはり、標準入力は一つなんだし、たとえインスタンスに別々の名前をつけていても、 ひとつをクローズしてしまえば、そのストリームは使えなくなるみたい。

Scanner と同じで、ストリームを開いてインスタンスを作ったら、それに対して いろいろとアクセスしなければならない。

で、最後に close処理をすることになるのかな。

カテゴリー: Java, memo

タグ: BufferedReader, java, Scanner, stdin, 標準入力

カウント: 204