Java 入門

Java スキャナ (Scanner) とコンソール入力

コンソールから入力を読み取ることは、プログラミングにおける最も基本的なスキルの1つです。これにより、プログラムはユーザーとインタラクティブに対話し、データを受け取り、その入力に基づいて特定のロジックを実行できるようになります。Javaでは、Scanner クラスを使用することで、整数、浮動小数点数、文字列など、コンソールからの様々な入力タイプを簡潔に読み取ることができます。

本章では、Scanner クラスを使用したコンソール入力の要点をカバーします。これには、Scanner オブジェクトの作成方法、異なるデータ型の読み取り、潜在的なエラーの処理、およびリソースリークを防ぐためのスキャナのクローズ方法が含まれます。

1. Scannerクラスを理解する

Scanner クラスは java.util パッケージに属しており、正規表現を使用してプリミティブ型や文字列をパース(解析)するメソッドを提供します。Scanner クラスを使用するには、まず Scanner オブジェクトを作成し、通常はコンソールを表す「標準入力ストリーム(System.in)」と関連付けます。

1.1 Scannerオブジェクトの作成

コンソールからデータを読み取るための Scanner オブジェクトを作成するには、以下の構文を使用します。

import java.util.Scanner; // Scannerクラスをインポート

public class InputExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // Scannerオブジェクトを作成
        // ... 残りのコード
    }
}
  • import java.util.Scanner;: この一行で Scanner クラスをインポートします。これがないと、コンパイラは Scanner が何を指しているのか理解できません。
  • Scanner scanner = new Scanner(System.in);: scanner という名前の新しいオブジェクトを作成します。System.in パラメータは、スキャナが標準入力ストリーム(通常はキーボード/コンソール)から読み取るべきであることを指定しています。

2. 様々なデータ型の読み取り

Scanner クラスは、入力ストリームからデータを読み取るための多様なメソッドを提供しています:

  • nextInt(): 整数値を読み取ります。
  • nextDouble(): 倍精度浮動小数点値を読み取ります。
  • nextFloat(): 単精度浮動小数点値を読み取ります。
  • nextBoolean(): 真偽値(Boolean)を読み取ります。
  • next(): 次のトークンを文字列として読み取ります(空白文字で区切られます)。
  • nextLine(): テキスト一行全体を読み取ります(スペースを含みます)。

2.1 総合的なコード例

import java.util.Scanner;

public class ReadDataTypes {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("整数を入力してください: ");
        int integerValue = scanner.nextInt();

        System.out.print("小数を入力してください: ");
        double doubleValue = scanner.nextDouble();

        System.out.print("テキストを入力してください: ");
        // ポイント:nextDouble() が残した改行コードを消費する
        scanner.nextLine();

        String stringValue = scanner.nextLine();

        System.out.println("整数: " + integerValue);
        System.out.println("小数: " + doubleValue);
        System.out.println("テキスト: " + stringValue);

        scanner.close(); // スキャナをクローズ
    }
}

       注意: nextInt()nextDouble() などのメソッドは、Enterキーを押した際に生成される「改行コード(\n)」を消費しません。そのため、直後に nextLine() を呼び出すと、その残留した改行コードを読み取ってしまい、空の文字列が返されてしまいます。これを防ぐために、バッファを「掃除」するための追加の nextLine() 呼び出しが必要になります。

3. 入力不一致例外 (InputMismatchException) のハンドリング

ユーザーが入力した型が期待される型と異なる場合(例えば、プログラムが整数を求めているのにユーザーが文字を入力した場合)、ScannerInputMismatchException をスローします。これは try-catch ブロックで処理できます。

import java.util.Scanner;
import java.util.InputMismatchException;

public class InputMismatch {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.print("整数を入力してください: ");
            int integerValue = scanner.nextInt();
            System.out.println("入力された値: " + integerValue);
        } catch (InputMismatchException e) {
            System.out.println("エラー:無効な入力です。整数を入力してください。");
            scanner.next(); // 重要:無効な入力を消費し、無限ループを防止する
        } finally {
            scanner.close();
        }
    }
}

4. デリミタ(区切り文字)の使用

デフォルトでは、Scanner は空白文字(スペース、タブ、改行)をデリミタとして使用します。これは useDelimiter() メソッドで変更可能です。

import java.util.Scanner;

public class DelimiterExample {
    public static void main(String[] args) {
        String input = "りんご,バナナ,オレンジ";
        Scanner scanner = new Scanner(input);
        scanner.useDelimiter(","); // カンマをデリミタに設定

        while (scanner.hasNext()) {
            System.out.println(scanner.next());
        }
        scanner.close();
    }
}

5. 実践的なユースケース

5.1 簡易加算器(ループによる読み取り)

ループを使用して、特定の条件が満たされるまで入力を受け取り続けることができます。

import java.util.Scanner;

public class InputLoop {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int sum = 0;
        int number;

        System.out.println("数値を入力して加算します(0を入力すると停止):");

        do {
            System.out.print("数値: ");
            number = scanner.nextInt();
            sum += number;
        } while (number != 0);

        System.out.println("合計: " + sum);
        scanner.close();
    }
}

5.2 CSV行のパース

この例では、カンマで区切られた一行のデータをパースする方法を示します。

import java.util.Scanner;

public class CSVReader {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("CSVデータを入力してください (例: 田中,太郎,30): ");
        String csvLine = scanner.nextLine();

        // ネストしたScannerを使用してこの行をパース
        Scanner lineScanner = new Scanner(csvLine);
        lineScanner.useDelimiter(",");
        
        String lastName = lineScanner.next();
        String firstName = lineScanner.next();
        int age = Integer.parseInt(lineScanner.next()); // 整数に変換

        System.out.println("姓: " + lastName + ", 名: " + firstName + ", 年齢: " + age);
        
        lineScanner.close();
        scanner.close();
    }
}