Java 中的 IlleagalStateException 与 NoSuchElementException 的区别?
在非法或不恰当的时间调用方法时,会抛出 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 异常。