はじめに (対象読者・この記事でわかること)
このページは、Javaの入門者から中級者までを対象にしています。特に、コンソールからの入力処理を初めて実装しようとしている方や、既にScannerを使っているが使い方に疑問を抱えている方に最適です。この記事を読むことで、java.util.Scanner の基本的な構文、各種メソッドの役割、入力ストリームの扱い方、さらにはパフォーマンスや例外処理に関するベストプラクティスが身につきます。実際のコード例を交えながら、標準入力・ファイル入力のシナリオ別に実装手順を解説するので、すぐに自分のプログラムに組み込めるようになります。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。 - Java の基礎文法(変数宣言、制御構文、メソッド定義など) - IDE(Eclipse、IntelliJ IDEA など)またはコマンドラインでのコンパイル・実行方法
Scanner の概要と基本的な使い方
Scanner は java.util パッケージに含まれるクラスで、テキスト入力をトークン(区切り文字)単位で読み取る機能を提供します。標準入力(System.in)だけでなく、ファイルや文字列からも簡単にデータを取得できる点が特徴です。内部的には正規表現エンジンを利用して区切り文字を判定し、nextInt() や nextLine() といったメソッドで型変換を行います。
主なコンストラクタは以下の通りです。
| コンストラクタ | 説明 |
|---|---|
new Scanner(InputStream source) |
System.in などのバイトストリームから読み込む |
new Scanner(File source) |
ファイルから直接読み込む |
new Scanner(Path source) |
java.nio.file.Path で指定したファイルを読む |
new Scanner(String source) |
文字列全体をソースとして扱う |
Scanner が内部で保持するバッファはデフォルトで 1024 バイトです。大量のデータを扱うときは useDelimiter() で区切り文字を変更したり、skip() で不要なトークンを飛ばすテクニックがあります。また、close() を忘れるとリソースリークの原因になるため、try-with-resources を使うのが推奨されます。
実践的な入力処理:ステップバイステップ実装
以下では、コンソールアプリケーションでユーザーから複数種類の入力を受け取り、簡単な計算を行うサンプルプログラムを作成します。実装は 3 つのステップに分けて解説します。
ステップ1: 基本的な入力取得
まずは Scanner のインスタンス化と、整数・文字列・小数の取得方法を確認します。
Javaimport java.util.Scanner; public class CalcApp { public static void main(String[] args) { try (Scanner sc = new Scanner(System.in)) { System.out.print("名前を入力してください: "); String name = sc.nextLine(); // 文字列取得 System.out.print("整数を 1 つ入力してください: "); int intVal = sc.nextInt(); // 整数取得 System.out.print("小数を 1 つ入力してください: "); double doubleVal = sc.nextDouble(); // 小数取得 System.out.printf("%s さん、入力された整数は %d、 小数は %.2f です。%n", name, intVal, doubleVal); } } }
ポイントは try-with-resources による自動クローズです。nextInt() や nextDouble() の直前で改行文字がバッファに残ることがあるため、次に nextLine() を呼ぶ場合は sc.nextLine() で余分な改行を消費しておくと安全です。
ステップ2: ループと例外処理を組み合わせる
次に、ユーザーが「終了」と入力するまで数値の足し算を繰り返すロジックを実装します。ここでは InputMismatchException を捕捉し、誤入力時に再入力を促す処理を加えます。
Javaimport java.util.InputMismatchException; import java.util.Scanner; public class SumLoop { public static void main(String[] args) { try (Scanner sc = new Scanner(System.in)) { int sum = 0; while (true) { System.out.print("整数を入力してください(終了するには exit と入力): "); String token = sc.next(); if ("exit".equalsIgnoreCase(token)) { break; } try { int value = Integer.parseInt(token); sum += value; System.out.println("現在の合計: " + sum); } catch (NumberFormatException e) { System.out.println("整数以外が入力されました。再度入力してください。"); } } System.out.println("最終合計は " + sum + " です。"); } } }
ここで sc.next() を使って空白区切りのトークンを取得し、parseInt で数値変換を行っています。NumberFormatException を捕まえているので、入力が整数でなくてもプログラムはクラッシュせずに再度入力を求めます。
ハマった点やエラー解決
1. nextInt() 後の改行が残っている
nextInt() 系メソッドは数値の後に続く区切り文字(通常は改行)をバッファに残します。そのまま nextLine() を呼ぶと空文字が返ってしまい、意図しない動作になります。対策は2つあります。
- nextInt() の直後に sc.nextLine(); を呼んで改行を消費する。
- nextLine() だけを使い、取得した文字列を Integer.parseInt() で変換する。
2. Scanner がファイルをロックしてしまう
new Scanner(File) でファイルを開くと、Java のデフォルトではファイルがロックされたままになることがあります。特に Windows 環境で同時に別プロセスがそのファイルに書き込もうとすると FileNotFoundException が発生します。解決策は FileInputStream を使い、Scanner にストリームを渡すことです。
JavaFileInputStream fis = new FileInputStream("data.txt"); Scanner fileScanner = new Scanner(fis);
3. 大量入力でのパフォーマンス低下
Scanner は正規表現ベースのパーサなので、1 行あたりの文字数が非常に長いと処理速度が低下します。大量データを処理する場合は BufferedReader と String.split() の組み合わせや、java.util.stream を利用した方が高速です。
解決策まとめ
| 問題 | 原因 | 解決策 |
|---|---|---|
nextInt() 後の空行 |
バッファに改行が残る | sc.nextLine() で消費、または文字列で取得して変換 |
| ファイルロック | Scanner(File) が排他ロックをかける |
FileInputStream 経由で Scanner を生成 |
| 大量データの遅延 | 正規表現パースのコスト | BufferedReader + split、または Stream を使用 |
まとめ
本稿では、Java 標準入力クラス Scanner の基礎から実務で役立つテクニックまでを網羅的に解説しました。
- 基本構文と主要メソッド:
nextInt(),nextLine(),useDelimiter()など - 安全なリソース管理:
try-with-resourcesによる自動クローズ - 実践的な入力パターン:ループ・例外処理・ファイル入力の組み合わせ
これらをマスターすれば、コンソールアプリや簡易的なデータ解析ツールを迅速に実装でき、ユーザーからの入力エラーにも柔軟に対応できるようになります。次回は Scanner の代替として BufferedReader と Stream を組み合わせた高速入力手法を取り上げる予定です。
参考資料
- Java SE 21 Documentation – Scanner
- Effective Java 第3版 – 章2. すべてのオブジェクトに共通のメソッドを設計する
- 「Java言語プログラミングレッスン」著:結城 浩(技術評論社)
