スキャナの入力ストリームにまだ値が残っているか確認する

Scanner クラスの next メソッドを実行すると、スキャナの入力ストリームから区切り文字が現れるまでの値を取得することができますが、取得できる値が入力ストリームに残っていない場合 NoSuchElementException 例外が発生します。そこで next メソッドを実行する前に入力ストリームに取得できる値が存在するかどうかを確認するために Scanner クラスの hasNext メソッドを利用します。ここではスキャナの入力ストリームにまだ値が残っているか確認する方法について解説します。

(Last modified: )

入力ストリームに取得できる値が残っているか確認する

まず次のサンプルを見てください。

import java.util.Scanner;

class JSample6_1{
  public static void main(String[] args){
    Scanner scanner = new Scanner("AB BC CA");

    System.out.println(scanner.next());
    System.out.println(scanner.next());
    System.out.println(scanner.next());
    System.out.println(scanner.next());
  }
}

入力ストリームとして文字列を指定したスキャナを作成したあと、 next メソッドを使って区切り文字までの値を取得し画面に表示しています。対象の文字列には取得できる値が 3 つ存在しますが、 next メソッドを 4 回実行しているため 4 回目の next メソッドを実行した時点で例外が発生します。

入力ストリームに取得できる値が残っているか確認する(1)

読み込む値の数が決まっている場合はいいのですが、読み込める値がいくつあるのか分からない場合、まだ読み込める値がある場合だけ読み込むようにする必要があります。このようなときに使用できるのが Scanner クラスの hasNext メソッドです。書式は次のとおりです。

public boolean hasNext()

戻り値:
このスキャナが別のトークンを保持する場合にのみtrue

例外:
IllegalStateException - このスキャナがクローズしている場合

このメソッドを実行するとスキャナの入力ストリームに読み込める値がある場合は true を返します。

次のサンプルを見てください。

import java.util.Scanner;

class JSample6_2{
  public static void main(String[] args){
    Scanner scanner = new Scanner("AB BC CA");

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

先ほどのサンプルを少し変更し、 hasNext メソッドを使って入力ストリームに値が残っている場合に値を取得して画面に表示するようにしました。

入力ストリームに取得できる値が残っているか確認する(2)

このように hasNext メソッドを使うことで、値が残っている間だけ繰り返し値を取得することができます。

次の値が指定したデータ型の値として取得できるか確認する

なお next メソッドと似たメソッドとして nextInt などのような取得する値のデータ型を指定するメソッドが複数用意されていますが、 hasNext メソッドについても同じように指定したデータ型の値が入力ストリームの次の値として取得できるか確認するために hasNextInt などのようなメソッドが用意されています。

public boolean hasNextBoolean()
public boolean hasNextByte()
public boolean hasNextByte(int radix)
public boolean hasNextShort()
public boolean hasNextShort(int radix)
public boolean hasNextInt()
public boolean hasNextInt(int radix)
public boolean hasNextLong()
public boolean hasNextLong(int radix)
public boolean hasNextFloat()
public boolean hasNextDouble()
public boolean hasNextBigInteger()
public boolean hasNextBigInteger(int radix)
public boolean hasNextBigDecimal()

また行単位で値を取得する nextLine メソッドに対応するメソッドとして hasNextLine メソッドも用意されています。

public boolean hasNextLine()

例えば入力ストリームに値が残っている場合でも、次の値が整数の値として識別できない値だった場合は hasNextInt メソッドは false を返します。

次のサンプルを見てください。

import java.util.Scanner;

class JSample6_3{
  public static void main(String[] args){
    Scanner scanner = new Scanner("16 42 RY 24");

    while (scanner.hasNextInt()){
      System.out.println(scanner.nextInt());
    }
  }
}

スキャナの入力ストリームに設定している文字列には、区切り文字で区切られた値が 4 つありますが、 3 つの目の値は hasNext メソッドであれば true を返しますが、 hasNextInt メソッドでは整数に変換できない値は false となるため、今回のサンプルでは 2 つの値を読み込んだあとで終了します。

次の値が指定したデータ型の値として取得できるか確認する(1)

なお 4 つ目の値は hasNextInt メソッドで true となる値ですが、 hasNextInt などのメソッドは取得できる値が残りの値のどこかにあるかどうかではなく、次の値が取得できるかどうかで反対するため、残りのインプットすトーラムにまだ取得できる値があったとしても次の値が取得できなければ false となります。

次の値が指定した文字列またはパターンとマッチするか確認する

スキャナの入力ストリームに取得できる値がまだある場合に、その値が指定した文字列や正規表現パターンとマッチするかどうかを調べることができます。指定した文字列と一致するか調べるには、引数に文字列を指定する Scanner クラスの hasNext メソッドを使用します。

public boolean hasNext(String pattern)

パラメータ:
pattern - スキャンするパターンを指定する文字列

戻り値:
このスキャナが指定されたパターンに一致する別のトークンを保持する場合にのみtrue

例外:
IllegalStateException - このスキャナがクローズしている場合

スキャナの入力ストリームから取得できる値が、 1 番目の引数に指定した文字列と一致する場合に true が戻り値として返されます。

次のサンプルを見てください。

import java.util.Scanner;

class JSample6_4{
  public static void main(String[] args){
    Scanner scanner = new Scanner("AB AB BC AB");

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

入力ストリームから取得できる値が "AB" と一致している間、値を取得します。

次の値が指定したデータ型の値として取得できるか確認する(1)

同じように取得できる次の値が指定した正規表現パターンとマッチするか調べるには、引数に Pattern オブジェクトを指定する Scanner クラスの hasNext メソッドを使用します。

public boolean hasNext(Pattern pattern)

パラメータ:
pattern - スキャンするパターン

戻り値:
このスキャナが指定されたパターンに一致する別のトークンを保持する場合にのみtrue

例外:
IllegalStateException - このスキャナがクローズしている場合

スキャナの入力ストリームから取得できる値が、 1 番目の引数に指定した Pattern オブジェクトとマッチする場合に true が戻り値として返されます。 Pattern オブジェクトの作成については「PatternオブジェクトとMatcherオブジェクトを作成する」を参照されてください。

次のサンプルを見てください。

import java.util.Scanner;
import java.util.regex.Pattern;

class JSample6_5{
  public static void main(String[] args){
    String regex = "[A-Z0-9]{2}";
    var p = Pattern.compile(regex);

    Scanner scanner = new Scanner("AB 7B DEB A5");

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

正規表現パターンとして A から Z または 0 から 9 までの文字が 2 つ続く文字列とマッチするものを作成しました。入力ストリームから取得できる値がこのパターンとマッチしている間、値を取得して画面に表示します。

次の値が指定したデータ型の値として取得できるか確認する(1)

このように次に取得できる値が指定した文字列と一致するか、または指定した正規表現パターンとマッチするかを調べることができます。

入力ストリームに標準入力を指定した場合の注意点

ここまで解説したように hasNext メソッドを使うと入力ストリームに取得できる値があるかどうかを調べることができますが、スキャナの入力ストリームとして標準入力を指定している場合は注意が必要です。

次のサンプルを見てください。

import java.util.Scanner;

class JSample6_6{
  public static void main(String[] args){

    Scanner scanner = new Scanner(System.in);

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

プログラムを実行すると最初の hasNext メソッドによってキーボードからの入力待ちとなります。

入力ストリームに標準入力を指定した場合の注意点(1)

ここでキーボードから "AB BC CA" と入力し、 Enter キーを押すとキーボードからの入力が完了し、区切り文字までの値を順に取得して画面に表示したあと再びキーボードからの入力待ちとなります。

入力ストリームに標準入力を指定した場合の注意点(2)

これは入力ストリームが標準入力の場合、取得できる値がない状態で hasNext メソッドを呼び出すと再びキーボードからの入力待ちとなるためです。キーボードから入力を行うと繰り返し処理が継続されるためいつまでも繰り返し処理が終わりません。

なおこの状態でもキーボードから Ctrl + z キーを押すたあとで Enter キーを押すと繰り返し処理が終了します。

入力ストリームに標準入力を指定した場合の注意点(3)

キーボードからの入力に対して、区切り文字までの値を順に取り出して処理したい場合には、行単位で取得したあとで取得した値を分割するようにされてみてください。具体的な手順は「区切り文字を無視して次の行までの値を受け取る」を参照されてください。

-- --

スキャナの入力ストリームにまだ値が残っているか確認する方法について解説しました。

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。