异常的背景
初始异常
除以 0数组下标越界 编译时异常 异常的基本用法
捕获异常异常程序的执行过程使用 try catch 处理异常的代码运行过程
出现多个异常 Java 的异常体系
父类 Exceptionfinallytry catch finally的返回值 异常处理流程自定义异常利用异常实现恢复模型
异常的背景 初始异常 除以 0代码如下:
public static void main(String[] args) { System.out.println(10/0); }
因为 0 不能做除数,所以会报异常:
代码如下:
public static void main(String[] args) { int[] arr = {1,2,3}; System.out.println(arr[9]); }
因为数组的下标最大是 2 ,这里是访问下标 9 ,所以会越界。
上面这些都是运行时异常,我们之前还遇到过编译时异常
使用类克隆的时候,如果不抛出异常的话,就会报错导致出现无法完成编译:
class Person implements Cloneable{ public int id; } public class Main{ public static void main(String[] args) { Person person = new Person(); Person person1 = (Person) person.clone(); } }
报异常如下:
如果重写克隆方法,并且抛出异常的话,程序就可以运行了。
class Person implements Cloneable{ public int id; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class Main{ public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); Person person1 = (Person) person.clone(); } }
这样程序就能运行了。
异常的基本用法 捕获异常通过 try catch 来捕获并且处理异常,代码如下:
try{ 有可能出现异常的语句 ; }[catch (异常类型 异常对象) { } ... ] [finally { 异常的出口 }]
try 代码块中放的是可能出现异常的代码.catch 代码块中放的是出现异常后的处理行为.finally 代码块中的代码用于处理善后工作, 会在最后执行.其中 catch 和 finally 都可以根据情况选择加或者不加. 异常程序的执行过程
在代码抛出异常之后,异常之后的代码就不执行了。代码如下:
public static void main(String[] args) { int[] arr = new int[]{1,2,3}; System.out.println(arr[5]); System.out.println("哈喽!!!"); }
运行结果如下:
在运行到异常的代码之后,报出异常之后下面的代码就不执行了。
代码如下:
public static void main(String[] args) { int[] arr = new int[]{1,2,3}; try { System.out.println(arr[5]); System.out.println("haha"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("捕捉到一个数组越界异常"); } System.out.println("哈喽!!!"); }
运行结果如下:
通过 try 来捕捉异常,然后通过 catch 来处理异常。try 捕捉到异常之后,异常下面的代码就不执行了。然后就是 catch 来执行,catch 执行完毕之后才可以继续往下执行。当然在 catch 当中也可以添加如下代码:
e.printStackTrace();
这里就是打印异常信息栈,输出异常的位置在哪里。交给 JVM 来处理异常,JVM 来处理的话,就会直接终止程序。
出现多个异常如果出现多个异常的话,就可以使用多个 catch 来捕捉异常。代码如下:
public static void main(String[] args) { int[] arr = new int[]{1,2,3}; try { arr = null; System.out.println(arr[5]); System.out.println("haha"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("捕捉到一个数组越界异常"); } catch (NullPointerException e) { System.out.println("捕捉到了空指针异常"); } System.out.println("哈喽!!!"); }
运行结果如下:
当然代码也能这样简写:
public static void main(String[] args) { int[] arr = new int[]{1,2,3}; try { arr = null; System.out.println(arr[5]); System.out.println("haha"); } catch (ArrayIndexOutOfBoundsException | NullPointerException e) { System.out.println("捕捉到一个数组越界 或者 空指针异常"); } System.out.println("哈喽!!!"); }
运行结果如下:
所有的异常都来自一个 throwable :
如果在 IDEA 当中查看异常的父子类关系时,就有如下关系图:
所有的异常都来自父类 Exception ,当然也可以在 catch 的时候直接写 Exception 。但是不建议这样做,因为这样就不知道是什么异常了。
注意:catch 在捕捉异常的时候,最好是先子类,再父类。这样就可以一阶一阶的处理异常。如果是先父类再子类的话,就会报错。
finally 一般用作资源的关闭。比如关闭 Scanner :
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); try { System.out.println(10 / n); } catch (InputMismatchException e) { e.printStackTrace(); System.out.println("输入有误"); } catch (ArithmeticException e){ e.printStackTrace(); System.out.println("算术异常,可能 0 做了除数"); } finally { scanner.close(); System.out.println("finally 执行了"); } }
不论是否发生异常,finally 都会执行:
就算交给 JVM 处理,还是会执行 finally 代码如下:
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); try { System.out.println(10 / n); } catch (InputMismatchException e) { e.printStackTrace(); System.out.println("输入有误"); } finally { scanner.close(); System.out.println("finally 执行了"); } }try catch finally的返回值
当 try 和 finally 当中都有返回的时候,结果是什么?
public static int func3() { int a = 10; try { return a; } catch (ArithmeticException e) { e.printStackTrace(); } finally { return 20; } } public static void main(String[] args) { int n = func3(); System.out.println(n); }
运行结果如下:
因为 finally 的特点是:不管抛没抛异常,finally 都会被执行。所以本来应该返回 a 的地方,就返回了 20 。所以:** 尽量避免在 finally 当中使用 return** 。
- 程序先执行 try 中的代码如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.如果找到匹配的异常类型, 就会执行 catch 中的代码如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).如果上层调用者也没有处理的了异常, 就继续向上传递.一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.
在自定义抛出异常的时候,用 throw 来抛出异常。
public static void func4(int x) throws RuntimeException { if(x == 10){ System.out.println(10 / x); throw new RuntimeException("x == 10"); } } public static void main(String[] args) { try { func4(10); } catch (ArithmeticException e) { e.printStackTrace(); } }
运行结果如下:
使用 while 循环建立类似 ”恢复模型“ 的异常处理行为,它将不断重复,直到异常不再抛出。
public static void main13(String[] args) { int i = 0; while (i < 10) { try { if (i < 10) { throw new RuntimeException("x < 10"); } } catch (RuntimeException e){ e.printStackTrace(); System.out.println("尝试处理异常"); i++; } } System.out.println("异常处理结束了"); }
运行结果如下:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)