Java 中的 IlleagalStateException 与 NoSuchElementException 的区别?

java 8object oriented programmingprogramming更新于 2025/6/26 21:37:17

在非法或不恰当的时间调用方法时,会抛出 IlleagalStateException 异常。

例如,ArrayList 类的 remove() 方法会在调用 next() 或 previous() 方法后删除最后一个元素。

  • 删除当前位置的元素后,需要移动到下一个元素才能将其删除,也就是说,每次调用 next() 方法只能调用一次 remove() 方法。
  • 由于列表的初始位置(指针)位于第一个元素之前,因此如果不调用 next() 方法,则无法调用此方法。

否则,如果调用 remove() 方法,则会抛出 java.lang.IllegalStateException 异常。

示例:在移动到第一个元素之前删除一个元素

import java.util.ArrayList;
import java.util.ListIterator;
public class NextElementExample{
   public static void main(String args[]) {
      //实例化 ArrayList 对象
      ArrayList<String> list = new ArrayList<String>();
      //填充 ArrayList
      list.add(&"apples");
      list.add(&"mangoes");
      //获取 ArrayList 的 Iterator 对象
      ListIterator<String> it = list.listIterator();
      //移除元素而不移动到第一个位置
      it.remove();
   }
}

运行时异常

Exception in thread "main" java.lang.IllegalStateException
at java.util.ArrayList$Itr.remove(Unknown Source)
at MyPackage.NextElementExample.main(NextElementExample.java:17)

示例:调用一次 next() 方法后调用两次 next() 方法

import java.util.ArrayList;
import java.util.ListIterator;
public class NextElementExample{
   public static void main(String args[]) {
      //实例化 ArrayList 对象
      ArrayList<String> list = new ArrayList<String>();
      //填充 ArrayList
      list.add(&"apples");
      list.add(&"mangoes");
      //获取 ArrayList 的 Iterator 对象
      ListIterator<String> it = list.listIterator();
      //移除元素但不移动到第一个位置
      it.next();
      it.remove();
      it.remove();
   }
}

输出

Exception in thread "main" java.lang.IllegalStateException
   at java.util.ArrayList$Itr.remove(Unknown Source)
   at MyPackage.NextElementExample.main(NextElementExample.java:17)

Trying to invoke this method within a loop also comes under this scenario.

it.next();
while(it.hasNext()) {
   it.remove();
}

解决方案

在上述场景中,要解决 IllegalStateException 问题,您需要正确调用 remove() 方法(仅在调用 next() 后调用一次)

示例

import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;
public class NextElementExample{
   public static void main(String args[]) {
      //实例化 ArrayList 对象
      ArrayList<String> list = new ArrayList<String>();
      //填充 ArrayList
      list.add(&"apples");
      list.add(&"mangoes");
      //获取 ArrayList 的 Iterator 对象
      ListIterator<String> it = list.listIterator();
      //移除元素但不移动到第一个位置
      System.out.println(Arrays.toString(list.toArray()));
      while(it.hasNext()) {
         it.next();
         it.remove();
      }  
      System.out.println(Arrays.toString(list.toArray()));
   }
}

输出

[apples, mangoes]
[]

同样,在每种情况下,为了处理非法状态异常,您需要在合法位置调用导致异常的方法。

NosuchElementException

在使用枚举、迭代器或标记器(tokenizer)的访问器方法(例如 next() 或 nextElement())访问集合、数组或其他对象的内容时,如果您尝试从空对象中获取元素,或者在到达对象(集合、数组或其他对象)的末尾后尝试获取下一个元素,则会生成 NoSuchElementException。

例如,

  • 如果对空枚举对象调用 Enumeration 类的 nextElement() 方法,或者如果当前位置位于枚举的末尾,则会在运行时生成 NosuchElementException。
  • 如果对空的 StringTokenizer 调用 StringTokenizer 类的 nextElement() 和 nextToken() 方法对象,或者,如果当前位置位于 StringTokenizer 的末尾,则运行时会抛出 NosuchElementException 异常。
  • 如果对空的 Iterator/ListIterator 对象调用 Iterator 或 ListIterator 类的 next() 方法,或者,如果当前位置位于末尾,则运行时会抛出 NosuchElementException 异常。
  • 同样,如果对空的 ListIterator 对象调用 ListIterator 类的 previous() 方法,或者,如果当前位置是 ListIterator 的开头,则运行时会抛出 NosuchElementException 异常。

示例

让我们考虑一个场景的完整示例

import java.util.StringTokenizer;
public class StringTokenizerExample{
   public static void main(String args[]) {
      String str = "Hello how are you";
      //实例化 StringTokenizer 类
      StringTokenizer tokenizer = new StringTokenizer(str, " ");
      //打印所有 token
      System.out.println(tokenizer.nextToken());
      System.out.println(tokenizer.nextToken());
      System.out.println(tokenizer.nextToken());
      System.out.println(tokenizer.nextToken());
      //到达末尾后获取下一个token
      tokenizer.nextToken();
      tokenizer.nextElement();
   }
}

Runtime error

Hello
how
are
you
Exception in thread "main" java.util.NoSuchElementException
   at java.util.StringTokenizer.nextToken(Unknown Source)
   at MyPackage.StringTokenizerExample.main(StringTokenizerExample.java:16)

解决方案

几乎所有访问器方法引发 NoSuchElementException 的类都包含各自的方法来验证对象(集合、标记器等)是否包含更多元素。

例如,

  • Enumeration 类包含一个名为 hasMoreElements() 的方法,如果当前对象在当前位置之后包含更多元素,则返回 true(否则返回 false)。
  • StringTokenizer 类包含名为 hasMoreTokens() 和 hasMoreElements() 的方法,如果当前对象在当前位置之后包含更多元素,则返回 true(否则返回 false)。
  • Iterator 类包含 hasNext() 方法,如果当前迭代器在当前位置之后包含更多元素,则该方法也返回 true(否则返回 false)。
  • ListIterator 类包含 hasPrevious() 方法,如果当前迭代器在当前位置之前包含更多元素,则该方法也返回 true(否则返回 false)。假)。

示例

import java.util.StringTokenizer;
public class StringTokenizerExample{
   public static void main(String args[]) {
      String str = "Hello how are you";
      //实例化 StringTokenizer 类
      StringTokenizer tokenizer = new StringTokenizer(str, " ");
      //打印所有标记
      while(tokenizer.hasMoreTokens()) {
         System.out.println(tokenizer.nextToken());
      }
   }
}

输出

Hello
how
are
you

区别

这两个异常的主要区别在于,当你在程序中非法位置调用方法时,会抛出 IllegalStateException 异常。

而当你尝试访问枚举、迭代器、StringTokenizer 等类的元素(使用访问器方法)时,如果这些类中已经没有其他元素,则会抛出 NoElementException 异常。


相关文章