Java初心者の天敵!Scannerで入力が飛ばされるバグの正体と解決策

こんにちは。ゆうせいです。

Javaを学び始めて、キーボードから文字を入力させるプログラムを作ってみたことはありますか?

「数字を入力させた後に、名前を入力させる」という単純なプログラムを書いたはずなのに、なぜか名前の入力が無視されて終わってしまう。そんな経験、ありませんか?

実はこれ、Javaの新人エンジニアが必ずと言っていいほど直面する「nextInt問題」と呼ばれる有名な現象なのです。

決してScannerクラスが壊れているわけではありません。

今回は、この不思議な現象の裏側にある「入力の仕組み」を解き明かしていきましょう!

あれ、名前が打てない?よくあるバグの再現

まずは、実際に問題が起きるコードを見てみましょう。

年齢を入力してもらい、その後に好きな食べ物を入力してもらうプログラムです。

import java.util.Scanner;

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

        System.out.print("年齢を入力してください:");
        int age = scanner.nextInt();

        System.out.print("好きな食べ物を入力してください:");
        String food = scanner.nextLine();

        System.out.println(age + "歳のあなたの好物は" + food + "ですね!");
    }
}

このプログラムを実行して「25」と打ち、エンターキーを押すとどうなるでしょうか。

本来なら「好きな食べ物を入力してください:」と表示されて止まるはずですが、実際には入力する隙もなくプログラムが終了してしまいます。

出力結果:

25歳のあなたの好物はですね!

食べ物の部分が空っぽです!一体、入力したはずのデータはどこへ消えてしまったのでしょうか?

犯人は「残された改行文字」!入力バッファの仕組み

なぜこのようなことが起きるのかを理解するために、「入力バッファ」という概念を知る必要があります。

入力バッファとは、キーボードから打ち込まれたデータが一時的に蓄えられる「待機場所」のようなものです。

私たちがキーボードで「25」と打ち込んでエンターキーを押したとき、入力バッファの中には以下のデータが入ります。

  1. 数字の「25」
  2. エンターキー(改行文字:\n)

ここで、nextIntメソッドの動きに注目してください。

nextIntは「数字だけ」をバッファから拾い上げます。

つまり、数字の「25」は変数ageに格納されますが、その直後にある「改行文字(\n)」はバッファの中に置き去りにされてしまうのです!

次にnextLineメソッドが呼ばれます。

nextLineは「バッファの中に改行文字を見つけるまでを読み込む」という性質を持っています。

しかし、先ほどの改行文字がすでにバッファの先頭に残っているため、nextLineは「あ、もう改行がある!入力は空っぽだな」と勘違いして、一瞬で処理を終えてしまうのです。

これが、入力が飛ばされたように見えるカラクリです。

nextIntとnextLineの違いを整理しよう

二つのメソッドの違いを整理してみましょう。

メソッド名読み取る範囲改行文字の扱い
nextInt()次の数値のみバッファに残す
nextLine()改行文字が出現するまでの一行すべてバッファから取り除いて捨てる

nextLineは「一行丸ごと掃除してくれる掃除機」のようなものですが、nextIntは「必要な部品(数字)だけをつまみ上げるピンセット」のようなものだと考えてください。

ピンセットを使った後は、ゴミ(改行文字)が残ってしまうのですね。

この問題を解決する2つのアプローチ

このバグを回避するには、主に2つの方法があります。

1. 空打ちで改行文字を掃除する

nextIntを使った直後に、あえてnextLineを一度呼び出す方法です。

これにより、バッファに残った改行文字を「掃除」して、次の入力に備えます。

System.out.print("年齢を入力してください:");
int age = scanner.nextInt();

// ここでバッファに残った改行文字を吸い出す!
scanner.nextLine(); 

System.out.print("好きな食べ物を入力してください:");
String food = scanner.nextLine();

2. すべてnextLineで受け取って変換する(実務推奨)

実務でよく使われるのは、そもそもnextIntを使わない方法です。

すべての入力をnextLineで「文字列」として受け取り、後から数字に変換します。

System.out.print("年齢を入力してください:");
String input = scanner.nextLine();
// 文字列を数値(int)に変換する
int age = Integer.parseInt(input);

System.out.print("好きな食べ物を入力してください:");
String food = scanner.nextLine();

この方法なら、常に一行ずつバッファをきれいにしながら進めるため、予期せぬ挙動に悩まされることがなくなります。

Integer.parseIntという専門的な処理が登場しますが、これは「文字列の"25"を計算に使える数値の25に変える魔法」だと思ってください。

理解度チェック!ミニクイズ

ここまでの内容を復習してみましょう。

  1. nextIntメソッドを実行した後、入力バッファに残ってしまうものは何ですか?
  2. nextLineメソッドは、どの文字が見つかるまでデータを読み込みますか?
  3. 実務において、入力バグを防ぐために推奨される入力方法はどちらですか?

正解:

  1. 改行文字(エンターキーの情報)
  2. 改行文字
  3. すべてnextLineで受け取ってから数値に変換する方法

まとめとこれからの学習指針

プログラムが思い通りに動かないとき、そこには必ず論理的な理由があります。

「Javaがバグっている」と疑う前に、データがコンピュータの中でどう流れているのかを想像してみることが、脱・初心者の第一歩です。

今後は、以下のステップで学習を進めてみてください。

  • 参照型と基本データ型の違いについて調べる(Stringとintは何が違うのか?)
  • 例外処理(try-catch)を学び、数字以外の文字が入力されたときにプログラムが止まらないようにする方法を知る

バッファの仕組みを理解したあなたは、もうScannerを怖がる必要はありません。

自信を持ってコードを書き進めていきましょう!

セイ・コンサルティング・グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。