一、基础知识
异常是用来描述代码中发生的异常情况的对象。当出现引起异常的情况时,就会抛出异常对象。方法可以选择自己处理异常或继续抛出异常。异常可以由Java运行时系统生成,也可以手动生成。由Java抛出的异常与违反语言规则或执行环境约束的基础性错误有关,手动生成的异常通常用于向方法的调用者报告某些错误条件。
二、异常类型
所有的异常类型都是Throwable的子类。Throwable位于异常类层次的顶部,紧随的两个分支是Exception和Error。Exception可用于捕获,也可用于自定义异常。Error则定义了在常规环境下不能由程序捕获的异常,通常是为了响应灾难性失败。
三、捕获异常
class Solution {
public static void main(String[] args) {
String s = "ABC";
try {
int a = Integer.parseInt(s);
System.out.println(a);
} catch (NumberFormatException exc) {
System.out.println("Unknown integer format");
}
}
}
异常被抛出后,程序控制就会立刻从try转移到catch中去。异常位置之后的语句不会执行。
import java.util.Scanner;
class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.nextLine();
String t = in.nextLine();
try {
int a = Integer.parseInt(s);
int b = Integer.parseInt(t);
System.out.println(a / b);
} catch (ArithmeticException exc) {
System.out.println("Divisor cannot be 0");
} catch (NumberFormatException exc) {
System.out.println("Unknown integer format");
}
}
}
单块代码可能会出现多种异常情况,可通过指定多条catch语句来捕获所有可能出现的异常。当异常抛出时,会按顺序检查每条catch语句,直到遇到可以匹配的catch语句,之后会忽略剩余的catch语句。若异常无法遇到匹配的catch语句,将会无法被捕获,程序会因异常而中断。
当使用多条catch语句时,子类异常捕获必须位于所有超类之前。若超类异常捕获位于子类之前,那么子类异常将永远无法被捕获。
四、内置异常
在Java内置的异常类中,最常用的是RuntimeException的子类。
所有方法不需要指明会抛出这些异常,称为未经检查的异常。
四、自定义异常
Exception类没有定义任何方法,但继承了Throwable提供的方法。
可通过继承Exception来实现自定义异常,可通过重写toString方法来修改异常描述。
import java.util.Scanner;
class MyException extends Exception {
MyException(String msg) {
super(msg);
}
@Override
public String toString() {
return "MyException: " + super.getMessage();
}
}
class Solution {
static int divide(int a, int b) throws MyException {
if (b == 0)
throw new MyException("Divisor cannot be 0");
return a / b;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a = in.nextInt();
int b = in.nextInt();
try {
int res = divide(a, b);
System.out.println(res);
} catch (MyException exc) {
System.out.println(exc);
}
}
}
五、链式异常
通过链式异常,可以为异常关联另一个异常。第二个异常是引发第一个异常的原因,称为引发异常或背后异常。可通过getCause方法获取当前异常的背后异常,通过initCause或构造函数关联背后异常,并且背后异常只能设置一次。
class Solution {
static void throwerA() {
IndexOutOfBoundsException exc = new IndexOutOfBoundsException("Index out of bounds");
exc.initCause(new NullPointerException());
throw exc;
}
static void throwerB() throws Exception {
throw new Exception("Null pointer cause exception", new NullPointerException());
}
public static void main(String[] args) {
try {
throwerA();
} catch (IndexOutOfBoundsException exc) {
System.out.println(exc.toString());
System.out.println(exc.getCause().toString());
}
try {
throwerB();
} catch (Exception exc) {
System.out.println(exc.toString());
System.out.println(exc.getCause().toString());
}
}
}
六、多重捕获
可通过单独的catch语句捕获多个异常。
import java.util.Scanner;
class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a = in.nextInt();
int b = in.nextInt();
int[] nums = {1, 2, 3};
try {
int res = a / b;
nums[a] = res;
} catch (ArithmeticException | ArrayIndexOutOfBoundsException exc) {
System.out.println(exc.toString());
}
}
}