校园招生网站建设的简报,html网页制作总结,工作室官网模板,做慧聪网站多少钱1.Java的异常体系
Java 内置了丰富的异常体系, 用来表示不同情况下的异常.
下图表示 Java 内置的异常类之间的继承关系: 来看下图#xff1a; 编译时异常意味着如果不处理这个异常的话#xff0c;编译时就不能通过#xff0c;直接飘红 运行时异常是运行的时候才发生的异常…1.Java的异常体系
Java 内置了丰富的异常体系, 用来表示不同情况下的异常.
下图表示 Java 内置的异常类之间的继承关系: 来看下图 编译时异常意味着如果不处理这个异常的话编译时就不能通过直接飘红 运行时异常是运行的时候才发生的异常 2.异常的核心思想
异常的核心思想就是EAFP.
EAFPIts Easier to Ask Forgiveness than Permission. 事后获取原谅比事前获取许可更容易. 也就是先操作, 遇到问题再处理.
所以说异常的核心思想其实就是程序先执行出现异常了再去解决
我们来看一段EAFP风格的代码稍后会对这段代码进行解释 try { 登陆游戏(); 开始匹配(); 游戏确认(); 选择英雄(); 载入游戏画面(); ... } catch (登陆游戏异常) { 处理登陆游戏异常; } catch (开始匹配异常) { 处理开始匹配异常; } catch (游戏确认异常) { 处理游戏确认异常; } catch (选择英雄异常) { 处理选择英雄异常; } catch (载入游戏画面异常) { 处理载入游戏画面异常; } 3.异常的基本用法
3.1捕获异常
基本语法 try{ 有可能出现异常的语句 ; }[catch (异常类型 异常对象) { } ... ] [finally { 异常的出口 }] 1:try 代码块中放的是可能出现异常的代码. 2:catch 代码块中放的是出现异常后的处理行为. 3:catch括号总放入的是可能会出现的异常类型和异常对象 4:finally 代码块中的代码用于处理善后工作, 会在最后执行. 5:其中 catch 和 finally 都可以根据情况选择加或者不加. 3.2代码示例
代码1 使用try catch来处理异常
1假设此时我们不用try catch来处理异常
public class yichang {public static void main(String[] args) {int a 0;System.out.println(10 / a);System.out.println(hh);}
} 运行后我们会发现此时最后一句输出语句根本不会被执行原因是System.out.println(10/a)这条语句发生了算数异常所以根本不会执行 System.out.println(hh); 这条语句. 总结假如不使用try catch处理异常的话便会交给jvm处理异常最终程序会异常终止且不会继续执行发生异常之后的代码. 当使用try catch来处理异常后
public class yichang {public static void main(String[] args) {int a 0;try {//try中存放的是可能会发生异常的代码System.out.println(10 / a);System.out.println(hhhh);} catch (ArithmeticException e) {//catch代码块放入的是处理异常的代码}System.out.println(hh);}
}//输出结果为hh
我们会发现当我们使用了try catch来处理了这个算术异常后此时输出结果为hh.
同样System.out.println(hhhh)这句话不会执行原因是在System.out.println(10/a)处发生了异常.
在来看一段代码
public class yichang {public static void main(String[] args) {int[] arr {1, 2, 3};try {System.out.println(before);System.out.println(arr[100]);System.out.println(after);} catch (ArrayIndexOutOfBoundsException e) {// 打印出现异常的调用栈e.printStackTrace();}System.out.println(after try catch);}
}//输出结果为beforejava.lang.ArrayIndexOutOfBoundsException: 100 at yichang.main(yichang.java:10)after try catch e.printStackTrace为打印出现异常的调用栈所以就会出现输出结果中的第二行的话
代码2 catch 只能处理对应种类的异常
继续来看下面的代码我们可以看到此时try中的代码会发生空指针异常但是catch中捕获的却是数组越界异常那么最终的System.out.println(after try catch);这条语句是不会被执行到的原因是catch中所捕获的异常类型与实际发生的异常不匹配所以处理异常失败。
public class yichang {public static void main(String[] args) {int[] arr {1, 2, 3};try {System.out.println(before);arr null;System.out.println(arr[100]);System.out.println(after);} catch (ArrayIndexOutOfBoundsException e) {/*e.printStackTrace();*/}System.out.println(after try catch);}
} 最终输出结果为 Exception in thread main java.lang.NullPointerException at yichang.main(yichang.java:11) before 代码3 catch可以捕获多个异常
方法1
public class yichang {public static void main(String[] args) {int[] arr {1, 2, 3};//catch代码块可以捕获多个异常try {System.out.println(before);System.out.println(arr[100]);//因为此时上面的代码发生了异常所以此时下面的代码是不会被执行的。System.out.println(after);} catch (ArithmeticException e) {e.printStackTrace();System.out.println(此段代码不会执行);} catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();System.out.println(捕获了数组越界异常);}System.out.println(after try catch);}
}//输出结果为before捕获了数组越界异常after try catchjava.lang.ArrayIndexOutOfBoundsException: 100 at yichang.main(yichang.java:11)
假如此时try中的代码发生的是数组下标越界异常但是第一个catch中捕获的却是算术异常那么这个catch中的代码是不会被执行的第二个catch捕获的是数组下标越界异常那么就会正常执行里面的代码,最后再执行System.out.println(after try catch);这条语句.
方法2
除了可以像上述那样捕获多个异常以外我们还可以通过|这个符号来捕获多个异常
如果多个异常的处理方式是完全相同, 也可以写成这样 catch (ArrayIndexOutOfBoundsException | NullPointerException e) { ... } public class yichang {public static void main(String[] args) {int[] arr {1, 2, 3};//catch代码块可以捕获多个异常try {System.out.println(before);System.out.println(arr[100]);//因为此时上面的代码发生了异常所以此时下面的代码是不会被执行的。System.out.println(after);} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {System.out.println(此段代码不会执行);e.printStackTrace();}System.out.println(after try catch);}
}//输出结果为before此段代码不会执行java.lang.ArrayIndexOutOfBoundsException: 100 at yichang.main(yichang.java:11)after try catch
代码4 也可以用一个 catch 捕获所有异常(不推荐)
public class yichang {public static void main(String[] args) {int[] arr {1, 2, 3};//也可以用一个 catch 捕获所有异常(不推荐)try {System.out.println(before);System.out.println(arr[100]);//因为此时上面的代码发生了异常所以此时下面的代码是不会被执行的。System.out.println(after);//由于 Exception 类是所有异常类的父类. 因此可以用这个类型表示捕捉所有异常.} catch (Exception e) {e.printStackTrace();System.out.println(此段代码会执行);}}
}//输出结果
before
java.lang.ArrayIndexOutOfBoundsException: 100 at yichang.main(yichang.java:11)
此段代码会执行 由于 Exception 类是所有异常类的父类. 因此可以用这个类型表示捕捉所有异常. 代码5 finally
finally表示最后的善后工作, 例如释放资源.
scanner对象此时表示的是一种资源资源最终要被释放
public class yichang {public static void main(String[] args) {//scanner中的close方法Scanner scanner new Scanner(System.in);try {int a scanner.nextInt();System.out.println(10 / a);} catch (ArithmeticException e) {e.printStackTrace();} finally {scanner.close();System.out.println(不管是否发生异常finally块都会永远被执行);}}
}//输出结果
java.lang.ArithmeticException: / by zero at yichang.main(yichang.java:13)
不管是否发生异常finally块都会永远被执行
注意无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行). 来看如下代码
public class yichang {public static void main(String[] args) {int a0;try {int ret10/a;}catch (ArrayIndexOutOfBoundsException e){}finally {System.out.println(hhhh);}}
}
输出结果为: hhhh Exception in thread main java.lang.ArithmeticException: / by zero at yichang.main(yichang.java:9) 可以看到此时我们并没有在catch中找到匹配的异常类型所以catch中的语句并不会执行但是finally中的语句是无论是否找到匹配的异常类型, finally 中的代码都会被执行到所以最终先输出hhh,再抛出算术异常.
代码6 使用try负责回收资源
刚才在代码5中我们使用finally来回收资源现在还有一种等价写法, 将 Scanner 对象在 try 的 ( ) 中创建, 就能保证在 try 执行完毕后自动调用 Scanner的 close 方法.最终在finally中也不再需要去调用close方法.
public class yichang {public static void main(String[] args) {try(Scanner scanner new Scanner(System.in)) {int a scanner.nextInt();System.out.println(10 / a);} catch (ArithmeticException e) {e.printStackTrace();} finally {System.out.println(不管是否发生异常finally块都会永远被执行);}}
}//输出结果
0
java.lang.ArithmeticException: / by zero at yichang.main(yichang.java:11)
不管是否发生异常finally块都会永远被执行
代码7 建议finally中不要使用return语句
public class yichang {public static int func() {try {int a 10;int ret 10 / a;return ret;} catch (Exception e) {e.printStackTrace();} finally {return 10;}}public static void main(String[] args) {System.out.println(func());}
}//输出结果
10
原因是当我们调用func函数其实最想获得的是10/a的返回值但是当我们在func函数中使用了finally之后func函数的返回值变为了finally函数中return出来的值不是我们想要的结果所以最终输出结果不是3而是10.所以我们并不建议在finally中使用return语句.
代码8 如果本方法中没有合适的处理异常的方式, 就会沿着调用栈向上传递 在下面代码中首先func方法并没有处理数组下标越界异常所以此时会沿着栈向上传递到main方法最终在main方法中找到了try catch来处理数组下标越界这个异常. public class yichang {public static void func3() {int[] arr {1, 2, 3};System.out.println(arr[100]);}public static void main(String[] args) {try {func3();} catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();}System.out.println(after try catch);}
}//输出结果
java.lang.ArrayIndexOutOfBoundsException: 100at yichang.func3(yichang.java:8)at yichang.main(yichang.java:13)
after try catch
代码示例9 如果向上一直传递都没有合适的方法处理异常, 最终就会交给 JVM 处理, 程序就会异常终止(和我们最开始未使用 try catch 时是一样的)
public class yichang {public static void func() {int[] arr {1, 2, 3};System.out.println(arr[100]);}public static void main(String[] args) {func();System.out.println(hhh);}
}
输出结果为 Exception in thread main java.lang.ArrayIndexOutOfBoundsException: 100 at yichang.func(yichang.java:8) at yichang.main(yichang.java:13) 可以看到, 程序已经异常终止了, 没有执行到 System.out.println(after try catch); 这一行.
总结
异常处理流程
1程序先执行 try 中的代码.
2如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配. 如果找到匹配的异常类型, 就会执行 catch 中的代码.
3如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
4无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行). 如果上层调用者也没有处理的了异常, 就继续向上传递.
5一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.
3.3声明和抛出异常
声明异常使用throws关键字
抛出异常使用throw关键字 一般声明异常和抛出异常都是搭配使用的一个方法执行体中抛出了异常后要在这个方法的后面声明抛出了哪些异常这样是为了告诉方法的调用者这个方法声明了哪些异常好让方法的调用者根据声明的不同异常来做出相应的处理操作下面来看代码
public class yichang {public static void func(int y) throws ArithmeticException,ArrayIndexOutOfBoundsException {if(y0){throw new ArithmeticException();}System.out.println(10/y);}public static void main(String[] args) {try {func(0);} catch (ArithmeticException|ArrayIndexOutOfBoundsException e) {System.out.println(jj);} finally {System.out.println(hh);}}
}
3.4异常小练习
第1题单选题
题目名称
关于Java的异常处理机制的叙述哪些正确
题目内容
A.如果程序发生错误及捕捉到异常情况了才会执行finally部分
B.其他选项都不正确
C.当try区段的程序发生异常且被catch捕捉到时才会执行catch区段的程序
D.catch部分捕捉到异常情况时才会执行finally部分 正确答案C 第2题单选题
题目名称
有关下述Java代码描述正确的选项是____。
public class TestClass {private static void testMethod() {System.out.println(testMethod);}public static void main(String[] args) {((TestClass)null).testMethod();}}
题目内容
A.编译不通过
B.编译通过运行异常报NullPointerException
C.编译通过运行异常报IllegalArgumentException
D.编译通过运行异常报NoSuchMethodException
E.编译通过运行异常报Exception
F.运行正常输出testMethod 正确答案F 解析因为testMethod方法为静态方法是不依赖于对象的所以最终经过类型强转后是可以正常输出的. 第3题单选题
题目名称
下列程序的运行结果
public void getCustomerInfo() {try {// do something that may cause an Exception} catch (java.io.FileNotFoundException ex) {System.out.print(FileNotFoundException!);} catch (java.io.IOException ex) {System.out.print(IOException!);} catch (java.lang.Exception ex) {System.out.print(Exception!);}}
题目内容
A.IOException!
B.IOException!Exception!
C.FileNotFoundException!IOException!
D.FileNotFoundException!IOException!Exception! 正确答案A 解析从题中我们可以看到Exception这个异常是IOException这个异常的父类而IOException是FileNotFoundException这个异常的父类所以从整个代码来看的话从上到下构成了子类到父类这样一个顺序当try中假设抛出了FileNotFoundException这个异常的话最终只会抛出对应 catch (java.io.FileNotFoundException ex)中的语句并不会将catch (java.io.IOException ex)和 catch (java.lang.Exception ex)这两个catch中的语句抛出。 反例假设此时我们变化catch的顺序那么最终会发生什么呢来看代码吧
public void getCustomerInfo() {try {// do something that may cause an Exception} catch (java.lang.Exception ex) {System.out.print(Exception!);} catch (java.io.IOException ex) {System.out.print(IOException!);} catch (java.io.FileNotFoundException ex) {System.out.print(FileNotFoundException!);}}
当我们变化顺序后当try中假设抛出了FileNotFoundException这个异常的话最终只会抛出对应 catch (java.lang.Exception ex)中的语句并不会将catch (java.io.IOException ex)和 catch (java.lang.FileNotFoundException ex)这两个catch中的语句抛出。
原因是Exception是FileNotFoundException的父类父类已经捕捉到这个异常了下面的catch语句当然不用再就继续捕捉了且不管顺序如何构成子父类关系的catch语句也只有一个会被执行 总结以后捕捉异常的时候从上往下一定注意顺序如果最上面是父类那么下面的捕捉语句都不会被执行所以应该先写子类的catch语句再写父类的catch语句。 第5题单选题
题目名称
下面有关JAVA异常类的描述说法错误的是
题目内容
A. 异常的继承结构基类为ThrowableError和Exception继承ThrowableRuntimeException和IOException等继承Exception
B.非RuntimeException一般是外部错误(非Error)其必须被 try{}catch语句块所捕获
C. Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形Error不需要捕捉
D.RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等必须被 try{}catch语句块所捕获 正确答案D 解析 A正确 B非RuntimeException包括了Error和编译时异常然后又加上非Error后就只剩下了编译时异常编译时异常是必须被try catch捕获的 C正确 D运行时异常不一定非要被try catch捕获不去捕获的话便会交给JVM去处理 4.自定义异常
注意事项 1自定义异常通常会继承自 Exception 或者 RuntimeException. 2继承自 Exception 的异常默认是受查异常(编译时异常). 3继承自 RuntimeException 的异常默认是非受查异常(运行时异常). 代码实例
代码1手动定义异常原因
在手动抛出异常的时候可以说明产生这个异常的原因在异常后面的括号内写入原因即可
public class yichang {public static void main(String[] args) {try {throw new ArithmeticException(抛出算术异常);} catch (ArithmeticException e) {e.printStackTrace();}}
}输出结果为 java.lang.ArithmeticException: 抛出算术异常 at yichang.main(yichang.java:14) 代码2自己定义一个异常类
第一种情况自己定义的这个异常类继承于RuntimeException
class MyException extends RuntimeException {public MyException(String message) {super(message);}
}public class yichang {public static void main(String[] args) {try {throw new MyException(抛出自己定义的异常);} catch (MyException e) {e.printStackTrace();}}
}
输出结果为 MyException: 抛出自己定义的异常 at yichang.main(yichang.java:16) 第二种情况自己定义的这个异常类继承于Exception
先来看两组代码
class MyException extends RuntimeException {public MyException(String message) {super(message);}
}public class yichang {public static void main(String[] args) {int a10;if(a10){throw new MyException(sss);}}
} 运行结果为 Exception in thread main MyException: sss at yichang.main(yichang.java:15) class MyException extends Exception {public MyException(String message) {super(message);}
}public class yichang {public static void main(String[] args) {int a10;if(a10){throw new MyException(sss);}}
}
运行结果报错截图如下 可以看到当我们自定义的异常类继承于RuntimeException且在主方法中并没有使用try catch捕获我们自定义的异常的时候最终会将异常交给我们的JVM处理因为运行时异常既可以被try catch捕获也可以交给JVM处理。 当我们自定义的异常类继承于Exception且在主方法中并没有使用try catch捕获我们自定义的异常的时候最终会报错原因是继承于Exception的异常类属于编译时异常也就是我们的受查异常必须被try catch捕获。 同时我们还要注意 假如在一个函数中所抛出(throw)的异常属于编译时异常且这些编译时异常在这个函数中并没有使用try catch进行处理那么首先需要在函数的后面声明(throws)异常并且在主函数中调用这个函数的时候使用try catch来处理这些编译时异常. 假如在一个函数中所抛出的异常属于编译时异常且这些编译时异常在这个函数中使用了try catch进行处理那么就不需要在函数的后面声明异常并且在主函数中调用这个函数的时候直接调用即可也不需要拿try catch进行捕获异常和处理操作. 代码示例
class MyException extends Exception {public MyException(String message) {super(message);}
}public class yichang {public static void print(int a) throws MyException {if (a 0) {throw new MyException(编译时异常);}}public static void main(String[] args) {try {print(0);} catch (MyException e) {System.out.println(hh);}}
} class MyException extends Exception {public MyException(String message) {super(message);}
}public class yichang {public static void print(int a) {try {if (a 0) {throw new MyException(编译时异常);}} catch (MyException e) {System.out.println(hh);}}public static void main(String[] args) {print(0);}
}