【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
**开源地址:https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB **
[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”);
}
}
//输出结果为
before
java.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 catch
java.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 a=0;
try {
int ret=10/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: 100
at 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(y==0){
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) {