一、基础知识
异常是用来描述代码中发生的异常情况的对象。当出现引起异常的情况时,就会抛出异常对象。方法可以选择自己处理异常或继续抛出异常。异常可以由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()); } } }