Java での NoSuchElementException エラーを修正する
- Java でイテレータを使用しているときに NoSuchElementException が発生する
- Java で列挙型を使用しているときに NoSuchElementException が発生する
- Java で StringTokenizer を使用しているときに NoSuchElementException が発生する
- Java でスキャナークラスを使用しているときに NoSuchElementException が発生する
例外は、プログラムの実行中に発生するイベントです。例外が発生すると、通常のプログラムフローが影響を受け、プログラムが異常終了します。このチュートリアルでは、java.util.NoSuchElementException
とそれを Java で処理する方法について説明します。
NoSuchElementException
は RuntimeException
クラスを継承します。これは、チェックされていない例外であることを意味します。チェックされていない例外は、実行時に発生するため、コンパイラによって処理されません。
NoSuchElementException
は、Scanner
クラス、Iterator
インターフェイス、Enumerator
インターフェイス、および StringTokenizer
クラスによってスローされます。これらのクラスには、イテラブルから次の要素をフェッチするためのアクセサのメソッドがあります。iterable
が空であるか、最大制限に達した場合、NoSuchElementException
をスローします。
さまざまなクラスが NoSuchElementException
をスローする方法を見てみましょう。
Java でイテレータを使用しているときに NoSuchElementException が発生する
Iterator
インターフェースには、反復の次の要素にアクセスするために使用される next()
と呼ばれるメソッドがあります。コレクションに要素がない場合は、NoSuchElementException
がスローされます。いくつかの例を見ていきます。
要素なしで HashMap
を反復しようとしています。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
// creating a hashmap with no element
HashMap<String, Integer> h1 = new HashMap<>();
// creating an iterator object
Iterator i = h1.keySet().iterator();
// trying to access element
i.next();
}
}
出力:
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1599)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1620)
at MyClass.main(MyClass.java:9)
HashMap
が空であるため、next()
メソッドは例外をスローします。hasNext()
メソッドを使用して、この例外を回避できます。iterable にさらに要素がある場合は、true を返します。
このような例外を回避するために、hasNext()
が True を返す場合にのみ、next()
メソッドを使用する必要があります。以下の例を参照してください。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
// creating a hashmap with no element
HashMap<String, Integer> h1 = new HashMap<>();
// creating an iterator object
Iterator i = h1.keySet().iterator();
// trying to access element
while (i.hasNext()) {
i.next();
}
}
}
このコードは例外をスローしません。HashMap
にいくつかの要素がある例を見て、要素を繰り返しましょう。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
// creating a hashmap
HashMap<String, Integer> h1 = new HashMap<>();
h1.put("one", 1);
h1.put("two", 2);
// creating an iterator object
Iterator i = h1.keySet().iterator();
// trying to access element
while (i.hasNext()) {
System.out.println(i.next());
}
}
}
出力:
one
two
hasNext()
メソッドがなければ、このコードは例外をスローしていましたが、正常に機能しています。
Java で列挙型を使用しているときに NoSuchElementException が発生する
Java では、Enumeration
には、列挙型の次の要素を返す nextElement()
というメソッドがあります。返す要素がない場合は、NoSuchElementException
がスローされます。
リストから列挙型を作成している以下の例を見てください。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
ArrayList<String> animals = new ArrayList<>();
animals.add(new String("elephant"));
// creating enumeration object
Enumeration en = Collections.enumeration(animals);
System.out.println(en.nextElement()); // gets "elephant"
System.out.println(en.nextElement()); // throws exception
}
}
出力:
elephant
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:970)
at java.base/java.util.Collections$3.nextElement(Collections.java:5440)
at MyClass.main(MyClass.java:9)
hasElement()
は、アクセスする ArrayList に要素が残っていないため、最初の要素を返した後に例外をスローします。この状況を回避するために、hasMoreElements()
メソッドを使用できます。
列挙に提供する要素がさらにある場合、このメソッドは true を返します。それ以外の場合は、false を返します。列挙にさらに要素がある場合にのみ、nextElement()
メソッドを呼び出すことができます。
以下の例を見てください。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
ArrayList<String> animals = new ArrayList<>();
animals.add(new String("elephant"));
// creating enumeration object
Enumeration en = Collections.enumeration(animals);
while (en.hasMoreElements()) {
System.out.println(en.nextElement()); // gets "elephant"
}
}
}
出力:
elephant
Java で StringTokenizer を使用しているときに NoSuchElementException が発生する
Java では、StringTokenizer
クラスは、nextToken()
と nextElement()
の 2つのメソッドを提供します。nextToken()
メソッドは文字列トークナイザーから次のトークン(文字列型)を返しますが、nextElement
メソッドは文字列ではなくオブジェクト型を返すことを除いて nexttoken()
に似ています。どちらのメソッドも NoSuchElementException
をスローします。
以下の例を参照してください。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String s = "I Love Delft";
StringTokenizer st = new StringTokenizer(s);
System.out.println(st.nextToken()); // gets I
System.out.println(st.nextToken()); // gets Love
System.out.println(st.nextToken()); // gets Delft
System.out.println(st.nextToken()); // Throws exception
}
}
出力:
I
Love
Delft
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.StringTokenizer.nextToken(StringTokenizer.java:347)
at MyClass.main(MyClass.java:9)
hasMoreTokens()
および hasMoreElements()
メソッドを使用して例外を回避できます。トークナイザーの文字列でより多くのトークンが使用可能な場合、どちらのメソッドも true を返します。hasMoreTokens()
メソッドが True を返す場合にのみ、nextToken()
メソッドを呼び出す必要があります。
以下の例を参照してください。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String s = "I Love Delft";
StringTokenizer st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
}
}
出力:
I
Love
Delft
Java でスキャナークラスを使用しているときに NoSuchElementException が発生する
Java の Scanner クラスは、next()
、nextInt()
などのいくつかのユーティリティメソッドを提供します。これらのメソッドを使用している間、NoSuchElementException
をスローできます。ここでそれらについて説明します。
- 標準入力にアクセスする 2つのスキャナーオブジェクトがあるとします。それらの 1つを閉じて、もう 1つを使用してメソッドを呼び出すと、
NoSuchElementException
がスローされます。以下の例を参照してください。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String s = "I Love Delft";
Scanner s1 = new Scanner(System.in);
Scanner s2 = new Scanner(System.in);
s1.close();
s2.next();
}
}
出力:
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Scanner.throwFor(Scanner.java:937)
at java.base/java.util.Scanner.next(Scanner.java:1478)
at MyClass.main(MyClass.java:8)
最初のスキャナーを閉じると、基になる InputStream
が閉じます。したがって、2 番目のスキャナーは同じ InputStream
から読み取ることができず、NoSuchElementException
をスローします。解決策は、1つのスキャナーオブジェクトを使用して System.in 入力を読み取ることです。
- スキャナーオブジェクトを使用して文字列またはファイルを読み取っているとします。読み取る行が残っていない場合は、例外が表示されます。以下の例を参照してください。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String s = "I Love Delft";
Scanner s1 = new Scanner(s);
System.out.println(s1.nextLine());
System.out.println(s1.nextLine());
}
}
出力:
I Love Delft
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.base/java.util.Scanner.nextLine(Scanner.java:1651)
at MyClass.main(MyClass.java:7)
この問題を解決するために、ブール値を返す hasNextLine()
メソッドを使用します。例を見てください。
import java.util.*;
public class Main {
public static void main(String args[]) {
String s = "I Love Delft";
Scanner s1 = new Scanner(s);
while (s1.hasNextLine()) {
System.out.println(s1.nextLine());
}
}
}
出力:
I Love Delft