本ページはプロモーションが含まれています

Java入門

JavaのScanner使い方!入力処理の基本と5つの重要ポイント

トム

・都内自社開発企業勤務/Javaバックエンドエンジニア
/Java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎 詳細なプロフィール

Java学習を始めたばかりのころ、コンソール画面からの入力処理でつまずいた経験はありませんか。多くの人が最初にぶつかる壁の一つが、この「入力処理」です。

「文字を入力したいだけなのに、なぜこんなにコードが長くなるのか」

「数値のあとに文字を入力しようとしたら、勝手にスキップされた」

このような悩みは、Javaの標準クラスであるScannerの特性を正しく理解すれば、すぐに解決できます。Scannerは直感的で使いやすい反面、内部のバッファの仕組みを知らないと思わぬ挙動をすることがあるからです。

この記事を読めば、Scannerを使った入力処理の基本から、実務でも通用する安全な実装方法、さらには誰もが一度はハマるエラーの回避策までを体系的に学べます。Javaでの入力処理に対する苦手意識を克服し、ユーザーと対話するプログラムを自由に作れるようになりましょう。

JavaのScannerとは?仕組みと役割をわかりやすく解説

Scannerとは、Javaのjava.utilパッケージに含まれる、入力を読み取るためのクラスです。結論から言えば、データを「単語」や「行」といった扱いやすい単位に分割して取り出すための、非常に便利なフィルターのような役割を果たします。

その理由は、コンピュータにとっての入力データは単なる「文字の羅列(ストリーム)」でしかないからです。Scannerを使うことで、その羅列の中から「次は整数が欲しい」「次は一行まるごと欲しい」といった指示出しが可能になります。

Scannerが入力処理で使われる理由

Scannerが多くの入門書や開発現場で採用される理由は、正規表現を使った高度な解析機能を、直感的なメソッドで利用できる点にあります。

例えば、空白で区切られた数値の羅列を読み込む場合、従来の基本的な手法では以下の手順が必要でした。

  1. 文字列として1行読み込む
  2. 空白で分割する
  3. それぞれを数値に変換する

しかし、Scannerを使えば「次の整数をくれ」とメソッドを呼ぶだけで、これらの処理を自動で行ってくれます。面倒な型変換や区切り文字の処理を隠蔽してくれるため、プログラマーはロジックの記述に集中できるのです。

Scannerで読み取れる入力の種類(標準入力/ファイル/文字列)

Scannerが読み取れるのは、キーボードからの入力だけではありません。主に以下の3つのソースに対応しています。

  • 標準入力(System.in):コンソール(コマンドプロンプトやターミナル)からのキーボード入力を受け取ります。最も一般的な利用シーンです。
  • ファイル(Fileオブジェクト):テキストファイルの内容を読み取ります。CSVのような単純なデータファイルの解析にも使われます。
  • 文字列(Stringオブジェクト):すでにプログラム内にある長い文字列を、特定のルールで分割したい場合に使用します。

このように、Scannerは入力元が何であれ、統一された操作方法でデータを抽出できる柔軟性を持っています。

JavaのScannerの基本的な使い方

ここでは、最も頻繁に使用するコンソール入力(標準入力)を例に、Scannerの具体的な操作方法を解説します。

Scannerのインスタンス生成とcloseすべき理由

Scannerを使うには、まずインスタンス(実体)を生成する必要があります。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // 標準入力を受け取るScannerを作成
        Scanner scanner = new Scanner(System.in);
        
        // ここで入力処理を行う
        
        // 最後に必ず閉じる
        scanner.close();
    }
}

使い終わったScannerは、必ずclose()メソッドで閉じる必要があります。

理由は、ScannerがOS(オペレーティングシステム)のリソースを占有しているからです。これを「リソースリーク」と呼びます。もし閉じ忘れると、メモリが無駄に使われたり、最悪の場合はファイルが開けなくなったりするトラブルにつながります。

next()とnextLine()の違い

初心者が最も混乱しやすいのが、文字列を読み取る2つのメソッドの違いです。

  • next():「次の区切り文字(空白や改行)」までの文字列を読み取ります。文中にスペースが含まれている場合、そこで読み込みが止まります。
  • nextLine():「行末(Enterキーが押される場所)」までのすべてを読み取ります。スペースを含んだ長い文章でも、1行まるごと取得できます。

例えば、「Hello Java World」と入力した場合の挙動は以下のようになります。

  • next() → "Hello" だけ取得(残りは次の読み込み待ちになる)
  • nextLine() → "Hello Java World" すべて取得

用途に応じて、これらを正しく使い分けることが重要です。

整数・小数・文字列を読み取る基本メソッド一覧

Scannerには、データの型に合わせて専用のメソッドが用意されています。

読み取りたい型メソッド説明
整数 (int)nextInt()次のトークンをint型として読み取る
長整数 (long)nextLong()大きな整数を読み取る
小数 (double)nextDouble()小数点を含む数値を読み取る
単語 (String)next()空白までの文字列を読み取る
1行 (String)nextLine()改行までの文字列を読み取る
真偽値 (boolean)nextBoolean()"true" または "false" を読み取る

これらのメソッドを使えば、わざわざInteger.parseInt()などで変換する必要がなく、コードが非常にすっきりします。

Scannerでよくあるつまずきポイント

Scannerを使っていると、多くの人が「なぜか入力が飛ばされる」という現象に遭遇します。これはバグではなく、Scannerの仕様によるものです。その仕組みを深く理解しましょう。

nextLine()だけがスキップされる問題の原因

最も典型的なトラブルは、nextInt()などの数値入力の直後にnextLine()を使った場合に発生します。

// 悪い例
int age = scanner.nextInt();
String name = scanner.nextLine(); // ここが入力を待たずに終了してしまう!

この現象が起きる理由は、nextInt()が「数値の部分だけ」を読み取り、入力の最後に押された「Enterキー(改行コード)」をバッファに残してしまうからです。

その直後に呼ばれたnextLine()は、残っていた改行コードを見つけて「あ、もう行の終わりだ」と判断し、空の文字列を返して終了してしまいます。

入力バッファとは何か(初学者が混乱する仕組み)

この現象を理解するには、「入力バッファ」という概念をイメージする必要があります。

キーボードから「20」と入力してEnterを押すと、コンピュータ内部のバッファには 20 だけでなく 20\n(\nは改行コード)というデータが溜まります。

  1. nextInt()が呼ばれる→ バッファから 20 を取り出す。→ バッファには \n が残る。
  2. nextLine()が呼ばれる→ バッファの先頭にある \n を見て「行が終わった」と判定する。→ 中身のない空文字を返す。

これが「スキップされた」と感じる原因です。

解決策は、数値入力のあとに一度空読みのnextLine()を入れることです。

int age = scanner.nextInt();
scanner.nextLine(); // 残った改行コードを空読みして捨てる
String name = scanner.nextLine(); // 正常に入力できる

ScannerをcloseするとSystem.inが使えなくなる理由

もう一つ注意すべき点は、Scannerを閉じると、その入力元であるSystem.in自体も閉じられてしまうことです。

一度System.inを閉じてしまうと、プログラムを再起動しない限り、二度と標準入力を受け取れなくなります。「メソッドの中でScannerを作って使い終わったらcloseする」という処理を繰り返すプログラムで、2回目以降にエラーになるのはこれが原因です。

標準入力を扱うScannerは、プログラム全体で1つだけ生成し、使い回すのが安全な設計です。

Scannerを使った実用サンプルコード

ここからは、実際にコピペして動かせるサンプルコードを紹介します。

コンソールからの連続入力を処理するサンプル

ユーザーが「exit」と入力するまで、入力を受け付け続けるチャットボット風のプログラムです。

import java.util.Scanner;

public class ChatBot {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("会話を始めます。「exit」で終了します。");
        
        while (true) {
            System.out.print("> ");
            String text = scanner.nextLine();
            
            if ("exit".equals(text)) {
                System.out.println("終了します。");
                break;
            }
            
            System.out.println("あなたの入力: " + text);
        }
        
        scanner.close();
    }
}

このコードでは、while(true)で無限ループを作り、特定のキーワードでループを抜ける構造にしています。対話型ツールを作る際の基本形です。

Scannerでファイルを読み込むサンプル

テキストファイルの内容を行ごとに読み取って表示する例です。ファイルのパスは環境に合わせて書き換えてください。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class FileReaderSample {
    public static void main(String[] args) {
        try {
            File file = new File("sample.txt");
            Scanner scanner = new Scanner(file);
            
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                System.out.println(line);
            }
            
            scanner.close();
        } catch (FileNotFoundException e) {
            System.out.println("ファイルが見つかりませんでした。");
        }
    }
}

ファイル操作では例外(エラー)が発生する可能性があるため、try-catch構文で囲む必要があります。hasNextLine()メソッドを使うことで、ファイルの終わりまで安全にループ処理が可能です。

文字列のトークン分割にScannerを使う応用例

カンマ区切りのデータ(CSVのような文字列)を分割する場合にもScannerは役立ちます。

import java.util.Scanner;

public class TokenizerSample {
    public static void main(String[] args) {
        String data = "Apple,Banana,Orange,Grape";
        Scanner scanner = new Scanner(data);
        
        // 区切り文字をカンマに設定
        scanner.useDelimiter(",");
        
        while (scanner.hasNext()) {
            System.out.println(scanner.next());
        }
        
        scanner.close();
    }
}

useDelimiter(",")を使うことで、空白以外の文字を区切りとして指定できます。簡単なデータ解析であれば、専用のライブラリを使わなくてもScannerだけで完結します。

Scannerより便利な代替手段はある?比較して理解する

Scannerは万能ですが、あらゆる場面で最適というわけではありません。状況によっては、他のクラスを使ったほうが良い場合もあります。

BufferedReaderとの違い(速度・用途・可読性)

Javaには古くからBufferedReaderというクラスが存在します。Scannerとの主な違いは「速度」と「機能」です。

  • Scanner:
    • メリット:解析機能が豊富(intやdoubleに直接変換できる)。
    • デメリット:処理速度が比較的遅い。
    • 用途:対話型プログラム、学習用、単純なファイル解析。
  • BufferedReader:
    • メリット:処理速度が非常に高速。大量のデータを読み込むのに向いている。
    • デメリット:文字列(String)としてしか読み込めないため、数値への変換処理を自分で書く必要がある。
    • 用途:競技プログラミング、大規模ログファイルの処理、高速性が求められるシステム。

結論として、普段の小規模な開発や学習用途であれば、書きやすさを優先してScannerを選ぶのが正解です。数万行を超えるデータを扱うようになったら、BufferedReaderを検討しましょう。

FilesクラスやStream APIとの組み合わせ方

Java8以降では、java.nio.file.FilesクラスとStream APIを使った、より現代的なファイル読み込みが主流になっています。

try (Stream<String> stream = Files.lines(Paths.get("sample.txt"))) {
    stream.forEach(System.out::println);
}

このように、Scannerを使わなくても非常に短いコードでファイルを処理できます。ただ、コンソールからのインタラクティブな入力に関しては、依然としてScannerが最も扱いやすいツールです。

Scannerを使うべき場面・避けるべき場面

これまでの比較を踏まえると、Scannerを使うべき場面は明確です。

  • 使うべき:ユーザー入力を受け付けるCLIツール、プログラミング学習、簡単なデータ変換、正規表現を使った柔軟な解析が必要な場合。
  • 避けるべき:パフォーマンスが厳しく問われる場合(数ミリ秒を削る必要がある)、非常に複雑なフォーマットのバイナリデータを扱う場合。

適材適所で使い分けることが、プロフェッショナルへの第一歩です。

JavaのScannerを安全に使うための注意点

最後に、実務レベルのコードを書くために知っておくべき、安全性を高めるテクニックを紹介します。

リソースリークを防ぐtry-with-resources

先ほどclose()が必要だと説明しましたが、Java7から導入された「try-with-resources」構文を使うと、勝手にcloseしてくれるようになります。書き忘れを防ぐためのベストプラクティスです。

try (Scanner scanner = new Scanner(System.in)) {
    System.out.print("入力してください: ");
    String input = scanner.nextLine();
    System.out.println(input);
} 
// ブロックを抜けると自動的にscanner.close()が呼ばれる

ただし、System.inを使う場合だけは注意が必要です。先述の通り、勝手にcloseされると困る場合(他の場所でも入力を使いたい場合)は、あえてこの構文を使わず、プログラム終了時に明示的に閉じる設計にすることもあります。

ユーザー入力の例外処理(NumberFormatException対策)

ユーザーは常に期待通りの入力をするとは限りません。「数値を入力してください」と言っても、「あ」と入力される可能性があります。

この場合、nextInt()はInputMismatchExceptionというエラーを吐いてプログラムが停止してしまいます。

System.out.print("数値を入力: ");
if (scanner.hasNextInt()) {
    int num = scanner.nextInt();
    System.out.println("数値です: " + num);
} else {
    System.out.println("数値ではありません。");
    scanner.next(); // 不正な入力を読み飛ばす
}

いきなり読み込むのではなく、hasNextInt()で「次は本当に整数か?」を確認してから読み込むことで、エラーによるクラッシュを防げます。

複数回入力を求める場合のベストプラクティス

繰り返し入力を求める場合、エラーハンドリングと組み合わせたメソッド化を行うと、コードの見通しが良くなります。

例えば、「正しい数値が入力されるまで何度でも聞き返す」という処理は頻出パターンです。これをメインメソッドにベタ書きするのではなく、getValidNumber(Scanner sc)のようなメソッドに切り出すことで、メインのロジックが驚くほどきれいになります。

まとめ:JavaのScannerを理解するとコンソール入力が一気に楽になる

今回はJavaのScannerクラスについて、基本的な使い方からバッファの仕組み、そして安全な実装パターンまで解説しました。

重要なポイントを振り返りましょう。

  1. Scannerはトークン分割が得意: 空白や改行でデータを区切って簡単に取り出せます。
  2. nextLine()の罠に注意: 数値入力のあとの改行コード残りには「空読み」で対処しましょう。
  3. バッファを意識する: 入力データはストリームとして流れてくることをイメージしてください。
  4. 型チェックを行う: hasNextInt()などを使い、ユーザーの誤入力で落ちないプログラムを作りましょう。
  5. 適材適所: 大量データにはBufferedReader、対話入力にはScannerと使い分けましょう。

Scannerは、Java初心者が最初に触れるクラスでありながら、その内部挙動にはプログラミングの重要な概念である「ストリーム」や「バッファ」が詰まっています。このクラスを自由に扱えるようになれば、ユーザーと対話する楽しいアプリケーション開発への扉が開かれます。

ぜひ、今回紹介したサンプルコードを書き換えて、自分だけの対話プログラムを作ってみてください。小さな成功体験の積み重ねが、あなたのプログラミングスキルを確実に向上させます。

  • この記事を書いた人
  • 最新記事

トム

・都内自社開発企業勤務/Javaバックエンドエンジニア
/Java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎 詳細なプロフィール

-Java入門