异常处理

异常

异常说明

异常的体系结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java.lang.Throwable
|-----java.lang.Error:一般不编写针对性的代码进行处理。
|-----java.lang.Exception:可以进行异常的处理
|------编译时异常(checked)
|-----IOException
|-----FileNotFoundException
|-----ClassNotFoundException
|------运行时异常(unchecked,RuntimeException)
|-----NullPointerException
|-----ArrayIndexOutOfBoundsException
|-----ClassCastException
|-----NumberFormatException
|-----InputMismatchException
|-----ArithmeticException

Java程序在执行过程中所发生的异常事件可分为两类

Error:Java虚拟机无法解决的严重问题,如JVM系统内部错误、资源耗尽等严重情况,比如StackOverflowError和OOM,一般不编写针对性代码进行处理

img

Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理,例如:空指针访问、试图读取不存在的文件、网络连接中断、数组角标越界

img

对于这些错误,一般有两种解决办法:

一是遇到错误就中止程序的运行,另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理

非受检查异常包括错误,运行时异常

受检查异常包括编译时异常

从程序执行过程,看编译时异常和运行时异常

img

编译时异常

执行javac.exe命名时,可能出现的异常

是指编译器要求必须处置的异常,即程序在运行时由于外部因素造成的一般性异常,编译器要求Java程序必须捕获或声明所有编译时异常

运行时异常

执行java.exe命名时,出现的异常

是指编译器不要求强制处理的异常,一般是指编程时的逻辑错误,是程序员应避免出现的错误,Java.lang.RuntimeException类以及它的子类都是运行时异常

对于这类异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响

常见的异常类型,请举例说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//******************以下是运行时异常***************************
//ArithmeticException
@Test
public void test6(){
int a = 10;
int b = 0;
System.out.println(a / b);
}

//InputMismatchException
@Test
public void test5(){
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();
System.out.println(score);

scanner.close();
}

//NumberFormatException
@Test
public void test4(){

String str = "123";
str = "abc";
int num = Integer.parseInt(str);
}

//ClassCastException
@Test
public void test3(){
Object obj = new Date();
String str = (String)obj;
}

//IndexOutOfBoundsException
@Test
public void test2(){
//ArrayIndexOutOfBoundsException
// int[] arr = new int[10];
// System.out.println(arr[10]);
//StringIndexOutOfBoundsException
String str = "abc";
System.out.println(str.charAt(3));
}

//NullPointerException
@Test
public void test1(){

// int[] arr = null;
// System.out.println(arr[3]);

String str = "abc";
str = null;
System.out.println(str.charAt(0));

}

//******************以下是编译时异常***************************
@Test
public void test7(){
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);

int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
fis.close();
}

image-20200205132239370

获取错误最理想的是在编译期,但有的错误只有在运行时才会发生。比如:除数为0数组下标越界等

分类:编译时异常和运行时异常

异常的处理

java异常处理的抓抛模型

过程一

“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出,一旦抛出对象以后,其后的代码就不再执行,这个过程称为抛出(throw)异常

关于异常对象的产生:

① 系统自动生成的异常对象

程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出

② 手动的生成一个异常对象,并抛出(throw)

Exception exception = new ClassCastException();

创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样

1577696087156

过程二

“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws+异常类型

如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理,如果异常没有在调用者方法中处理,它会继续被抛给这个调用方法的上层方法。这个过程将一直继续下去,直到异常被处理

这个过程称为捕获(catch)异常

如果一个异常回到main()方法,并且main()也不处理,则程序运行中止

程序员通常只能处理Exception,而对Error无能为力

异常处理方式一

try-catch-finally

try

捕获异常的第一步是用try{}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中

catch(Exception e)

在catch语句块中是对异常对象进行处理的代码,每个try语句块可以伴随一个或者多个catch语句,用于处理可能产生的不同类型的异常对象

如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数比 如 : 可 以用ArithmeticException类作为参数的地方,就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)

finally

捕获异常的最后一步是通过finally语句处理提供一个统一的出口,使得在控制流转到程序的其他部分以前能够对程序的状态作统一的管理

不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否由异常,catch语句中是否有return,finally块中的语句都会被执行

finally语句和catch语句是任选的

使用说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
try{
//可能出现异常的代码

}catch(异常类型1 变量名1){

//处理异常的方式1

}catch(异常类型2 变量名2){

//处理异常的方式2

}catch(异常类型3 变量名3){

//处理异常的方式3

}
....

finally{

//一定会执行的代码

}

说明

  1. finally是可选的。

  2. 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配

  3. 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没写finally的情况)继续执行其后的代码

  4. catch中的异常类型如果没子父类关系,则谁声明在上,谁声明在下无所谓。

    catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错

  5. 常用的异常对象处理的方式:

    与其他对象一样,可以访问一个异常对象的成员变量或调用它的方法

    String getMessage():获取异常信息,返回字符串

    printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置,返回值为void

    1577703607012

  6. 在try结构中声明的变量,再出了try结构以后,就不能再被调用

  7. try-catch-finally结构可以嵌套

不捕获异常时的情况

在使用RuntimeException类或是它的子类,这些类的异常的特点是,即使没有使用try和catch捕获,Java自己也能捕获,并且编译通过,但运行时会发生异常使得程序运行终止

如果抛出的异常是IOException等类型的非运行时异常,则必须捕获,否则编译错误,也就是说,我们必须处理编译时异常,将异常进行捕获,转化为运行时异常

总结

如何看待代码中的编译时异常和运行时异常?

体会1:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。

体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。

定义+赋值=初始化

finally的再说明

  1. finally是可选的

  2. finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中return语句,catch中return语句等情况。

  3. 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

对于运行时异常实际上不进行异常处理,编译时异常一定要进行try-catch

img

重点

1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testMethod(){
int num= Method();
System.out.println(num);
}

private int Method() {
try {
int[] arr=new int[10];
System.out.println(arr[10]);
System.out.println(arr[0]);
return 1;
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组越界1");
e.printStackTrace();
System.out.println("数组越界2");
return 2;
}finally {
System.out.println("我一定会执行");
return 3;
}
}

输出结果

image-20200205154929178

有finally,且在finally中有return的时候

在出现异常的时候,会直接从异常处跳出并进入catch中,执行catch中的所有语句,但不执行catch中的return语句,再执行finally中的所有语句,并返回finally中的return结果

image-20200205160922322

2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testMethod(){
int num= Method();
System.out.println(num);
}

private int Method() {
try {
int[] arr=new int[10];
//System.out.println(arr[10]);
System.out.println(arr[0]);
return 1;
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组越界1");
e.printStackTrace();
System.out.println("数组越界2");
return 2;
}finally {
System.out.println("我一定会执行");
return 3;
}
}

输出结果

image-20200205163426410

没有出现异常,则会正常执行,并执行finally中的语句,输出finally中的return结果

3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testMethod(){
int num= Method();
System.out.println(num);
}

private int Method() {
try {
int[] arr=new int[10];
System.out.println(arr[10]);
System.out.println(arr[0]);
return 1;
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组越界1");
e.printStackTrace();
System.out.println("数组越界2");
return 2;
}finally {
System.out.println("我一定会执行");
//return 3;
}
}

输出结果

image-20200205161103651

只有fianlly,但是没有return

在出现异常的时候,会直接从异常处跳出并进入catch中,执行catch中的所有语句,但不执行catch中的return语句,再执行finally中的所有语句,并返回catch中的return结果

4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testMethod(){
int num= Method();
System.out.println(num);
}

private int Method() {
try {
int[] arr=new int[10];
//System.out.println(arr[10]);
System.out.println(arr[0]);
return 1;
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组越界1");
e.printStackTrace();
System.out.println("数组越界2");
return 2;
}finally {
System.out.println("我一定会执行");
//return 3;
}
}

输出结果

image-20200205162525653

在没有出现异常的时候,会正常输出,但不会输出try中的return语句,而执行finally中的语句和return语句

异常处理基础介绍

先来看看异常处理的语法格式

try{ … } catch(Exception e){ … } finally{ … }

其中,

  • try:是用来监测可能会出现异常的代码段。
  • catch:是用来捕获 try 代码块中某些代码引发的异常,如果 try 里面没有异常发生,那么 catch 也一定不会执行。在 Java 语言中,try 后面可以有多个 catch 代码块,用来捕获不同类型的异常,需要注意的是前面的 catch 捕获异常类型一定不能包含后面的异常类型,这样的话,编译器会报错。
  • finally:不论 try-catch 如何执行,finally 一定是最后执行的代码块,所有通常用来处理一些资源的释放,比如关闭数据库连接、关闭打开的系统资源等。

异常处理的基本使用,具体可以参考下面的代码段:

1
2
3
4
5
6
7
try {
int i = 10 / 0;
} catch (ArithmeticException e) {
System.out.println(e);
} finally {
System.out.println("finally");
}

多 catch 的使用,具体可以参考下面的代码段:

1
2
3
4
5
6
7
8
9
try {
int i = Integer.parseInt(null);
} catch (ArithmeticException ae) {
System.out.println("ArithmeticException");
} catch (NullPointerException ne) {
System.out.println("NullPointerException");
} catch (Exception e) {
System.out.println("Exception");
}

需要注意的是 Java 虚拟机会从上往下匹配错误类型,因此前面的 catch 异常类型不能包含后面的异常类型。比如上面的代码如果把 Exception 放在最前面编译器就会报错,具体可以参考下面的图片。

enter image description here

异常处理的发展

随着 Java 语言的发展,JDK 7 的时候引入了一些更加便利的特性,用来更方便的处理异常信息,如 try-with-resources 和 multiple catch,具体可以参考下面的代码段:

1
2
3
4
5
6
try (FileReader fileReader = new FileReader("");
FileWriter fileWriter = new FileWriter("")) { // try-with-resources
System.out.println("try");
} catch (IOException | NullPointerException e) { // multiple catch
System.out.println(e);
}

异常处理的基本原则

先来看下面这段代码,有没有发现一些问题?

1
2
3
4
5
try {
// ...
int i = Integer.parseInt(null);
} catch (Exception e) {
}

以上的这段代码,看似“正常”,却违背了异常处理的两个基本原则:

  • 第一,尽量不要捕获通用异常,也就是像 Exception 这样的异常,而是应该捕获特定异常,这样更有助于你发现问题;
  • 第二,不要忽略异常,像上面的这段代码只是加了 catch,但没有进行如何的错误处理,信息就已经输出了,这样在程序出现问题的时候,根本找不到问题出现的原因,因此要切记不要直接忽略异常。

异常处理对程序性能的影响

异常处理固然好用,但一定不要滥用,比如下面的代码片段:

1
2
3
4
5
6
7
8
9
// 使用 com.alibaba.fastjson
JSONArray array = new JSONArray();
String jsonStr = "{'name':'laowang'}";
try {
array = JSONArray.parseArray(jsonStr);
} catch (Exception e) {
array.add(JSONObject.parse(jsonStr));
}
System.out.println(array.size());

这段代码是借助了 try-catch 去处理程序的业务逻辑,通常是不可取的,原因包括下列两个方面。

  • try-catch 代码段会产生额外的性能开销,或者换个角度说,它往往会影响 JVM 对代码进行优化,因此建议仅捕获有必要的代码段,尽量不要一个大的 try 包住整段的代码;与此同时,利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句(if/else、switch)要低效。
  • Java 每实例化一个 Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。

以上使用 try-catch 处理业务的代码,可以修改为下列代码:

1
2
3
4
5
6
7
8
9
10
11
12
// 使用 com.alibaba.fastjson
JSONArray array = new JSONArray();
String jsonStr = "{'name':'laowang'}";
if (null != jsonStr && !jsonStr.equals("")) {
String firstChar = jsonStr.substring(0, 1);
if (firstChar.equals("{")) {
array.add(JSONObject.parse(jsonStr));
} else if (firstChar.equals("[")) {
array = JSONArray.parseArray(jsonStr);
}
}
System.out.println(array.size());

异常处理方式二

“throws + 异常类型”写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。

一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码,就不再执行!

如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示的抛出异常,表名该方法将不对这些异常进行处理,而是由该方法的调用者负责处理

在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以时方法中产生的异常类型,也可以是它的父类

重写方法声明抛出异常的原则

重写方法不能抛出比重写方法范围更大的异常类型,在多态的情况下,对methodA()方法的调用如果出现异常,则异常的捕获按父类声明的异常处理

1
2
3
4
5
6
7
8
9
10
11
12
public class A {
public void methodA() throws IOException {
……
} }
public class B1 extends A {
public void methodA() throws FileNotFoundException {
……
} }
public class B2 extends A {
public void methodA() throws Exception { //报错
……
} }

对比两种处理方式

try-catch-finally:真正的将异常给处理掉了。

throws的方式只是将异常抛给了方法的调用者。并没真正将异常处理掉。

体会开发中应该如何选择两种处理方式?

  • 如果父类中被重写的方法没throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中异常,必须使用try-catch-finally方式处理。

  • 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。

补充:

方法重写的规则之一:

子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型

手动抛出异常对象

使用说明

在程序执行中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常类的对象。

面试题

throw 和 throws区别:

throw 表示抛出一个异常类的对象,生成异常对象的过程。声明在方法体内。

throws 属于异常处理的一种方式,声明在方法的声明处。

典型例题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
//手动抛出异常对象
//throw new RuntimeException("您输入的数据非法!");
//throw new Exception("您输入的数据非法!");
throw new MyException("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}

自定义异常类

如何自定义一个异常类?

用户自定义异常类MyException,用于描述数据取值范围错误信息,用户自己的异常类必须继承现有的异常类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
* 如何自定义异常类?
* 1. 继承于现的异常结构:RuntimeException 、Exception
* 2. 提供全局常量:serialVersionUID
* 3. 提供重载的构造器
* 4. 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型
*/
public class MyException extends Exception{

static final long serialVersionUID = -7034897193246939L;

public MyException(){

}

public MyException(String msg){
super(msg);
}
}

相关面试题

1. try 可以单独使用吗?

答:try 不能单独使用,否则就失去了 try 的意义和价值。

2. 以下 try-catch 可以正常运行吗?

1
2
3
4
5
try {
int i = 10 / 0;
} catch {
System.out.println("last");
}

答:不能正常运行,catch 后必须包含异常信息,如 catch (Exception e)。

3. 以下 try-finally 可以正常运行吗?

1
2
3
4
5
try {
int i = 10 / 0;
} finally {
System.out.println("last");
}

答:可以正常运行。

4. 以下代码 catch 里也发生了异常,程序会怎么执行?

1
2
3
4
5
6
7
8
9
10
try {
int i = 10 / 0;
System.out.println("try");
} catch (Exception e) {
int j = 2 / 0;
System.out.println("catch");
} finally {
System.out.println("finally");
}
System.out.println("main");

答:程序会打印出 finally 之后抛出异常并终止运行。

5. 以下代码 finally 里也发生了异常,程序会怎么运行?

1
2
3
4
5
6
7
8
9
try {
System.out.println("try");
} catch (Exception e) {
System.out.println("catch");
} finally {
int k = 3 / 0;
System.out.println("finally");
}
System.out.println("main");

答:程序在输出 try 之后抛出异常并终止运行,不会再执行 finally 异常之后的代码。

6. 常见的运行时异常都有哪些?

答:常见的运行时异常如下:

  • java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象;
  • java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误,通常是程序

试图通过字符串来加载某个类时引发的异常;

  • java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符;
  • java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生;
  • java.lang.ClassCastException 数据类型转换异常;
  • java.lang.NoClassDefFoundException 未找到类定义错误;
  • java.lang.NoSuchMethodException 方法不存在异常;
  • java.lang.IllegalArgumentException 方法传递参数错误。

7. Exception 和 Error 有什么区别?

答:Exception 和 Error 都属于 Throwable 的子类,在 Java 中只有 Throwable 及其之类才能被捕获或抛出,它们的区别如下:

  • Exception(异常)是程序正常运行中,可以预期的意外情况,并且可以使用 try/catch 进行捕获处理的。Exception 又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception),运行时异常编译能通过,但如果运行过程中出现这类未处理的异常,程序会终止运行;而受检查的异常,要么用 try/catch 捕获,要么用 throws 字句声明抛出,否则编译不会通过。
  • Error(错误)是指突发的非正常情况,通常是不可以恢复的,比如 Java 虚拟机内存溢出,诸如此类的问题叫做 Error。

8. throw 和 throws 的区别是什么?

答:它们的区别如下:

  • throw 语句用在方法体内,表示抛出异常由方法体内的语句处理,执行 throw 一定是抛出了某种异常;
  • throws 语句用在方法声明的后面,该方法的调用者要对异常进行处理,throws 代表可能会出现某种异常,并不一定会发生这种异常。

9. Integer.parseInt(null) 和 Double.parseDouble(null) 抛出的异常一样吗?为什么?

答:Integer.parseInt(null) 和 Double.parseDouble(null) 抛出的异常类型不一样,如下所示:

  • Integer.parseInt(null) 抛出的异常是 NumberFormatException;
  • Double.parseDouble(null) 抛出的异常是 NullPointerException。

至于为什么会产生不同的异常,其实没有特殊的原因,主要是由于这两个功能是不同人开发的,因而就产生了两种不同的异常信息。

10. NoClassDefFoundError 和 ClassNoFoundException 有什么区别?

  • NoClassDefFoundError 是 Error(错误)类型,而 ClassNoFoundExcept 是 Exception(异常)类型;
  • ClassNoFoundExcept 是 Java 使用 Class.forName 方法动态加载类,没有加载到,就会抛出 ClassNoFoundExcept 异常;
  • NoClassDefFoundError 是 Java 虚拟机或者 ClassLoader 尝试加载类的时候却找不到类订阅导致的,也就是说要查找的类在编译的时候是存在的,运行的时候却找不到,这个时候就会出现 NoClassDefFoundError 的错误。

11. 使用 try-catch 为什么比较耗费性能?

答:这个问题要从 JVM(Java 虚拟机)层面找答案了。首先 Java 虚拟机在构造异常实例的时候需要生成该异常的栈轨迹,这个操作会逐一访问当前线程的栈帧,并且记录下各种调试信息,包括栈帧所指向方法的名字,方法所在的类名、文件名,以及在代码中的第几行触发该异常等信息,这就是使用异常捕获耗时的主要原因了。

12. 常见的 OOM 原因有哪些?

答:常见的 OOM 原因有以下几个:

  • 数据库资源没有关闭;
  • 加载特别大的图片;
  • 递归次数过多,并一直操作未释放的变量。

13. 以下程序的返回结果是?

1
2
3
4
5
6
7
8
public static int getNumber() {
try {
int number = 0 / 1;
return 2;
} finally {
return 3;
}
}

A:0

B:2

C:3

D:1

答:3

题目解析:程序最后一定会执行 finally 里的代码,会把之前的结果覆盖为 3。

14. finally、finalize 的区别是什么?

答:finally、finalize 的区别如下:

  • finally 是异常处理语句的一部分,表示总是执行;
  • finalize 是 Object 类的一个方法,子类可以覆盖该方法以实现资源清理工作,垃圾回收之前会调用此方法。

15. 为什么 finally 总能被执行?

答:finally 总会被执行,都是编译器的作用,因为编译器在编译 Java 代码时,会复制 finally 代码块的内容,然后分别放在 try-catch 代码块所有的正常执行路径及异常执行路径的出口中,这样 finally 才会不管发生什么情况都会执行。

注:

final、finally、finalize三者的区别?

Final、finally是关键字 finalize是方法名

类似:

throw 和 throws

Collection 和 Collections

String 、StringBuffer、StringBuilder

ArrayList 、 LinkedList

HashMap 、LinkedHashMap

重写、重载

结构不相似的:

抽象类、接口

== 、 equals()

sleep()、wait()

总结

image-20200205165448662

文章目录
  1. 1. 异常
    1. 1.1. 异常说明
      1. 1.1.1. 异常的体系结构
      2. 1.1.2. 从程序执行过程,看编译时异常和运行时异常
        1. 1.1.2.1. 编译时异常
        2. 1.1.2.2. 运行时异常
      3. 1.1.3. 常见的异常类型,请举例说明
    2. 1.2. 异常的处理
      1. 1.2.1. java异常处理的抓抛模型
        1. 1.2.1.1. 过程一
        2. 1.2.1.2. 过程二
      2. 1.2.2. 异常处理方式一
        1. 1.2.2.1. try
        2. 1.2.2.2. catch(Exception e)
        3. 1.2.2.3. finally
        4. 1.2.2.4. 使用说明
        5. 1.2.2.5. 说明
        6. 1.2.2.6. 不捕获异常时的情况
        7. 1.2.2.7. 总结
        8. 1.2.2.8. finally的再说明
        9. 1.2.2.9. 重点
      3. 1.2.3. 异常处理基础介绍
      4. 1.2.4. 异常处理的发展
      5. 1.2.5. 异常处理的基本原则
      6. 1.2.6. 异常处理对程序性能的影响
      7. 1.2.7. 异常处理方式二
        1. 1.2.7.1. 重写方法声明抛出异常的原则
      8. 1.2.8. 对比两种处理方式
      9. 1.2.9. 体会开发中应该如何选择两种处理方式?
      10. 1.2.10. 手动抛出异常对象
        1. 1.2.10.1. 使用说明
        2. 1.2.10.2. 面试题
        3. 1.2.10.3. 典型例题
        4. 1.2.10.4. 自定义异常类
    3. 1.3. 相关面试题
      1. 1.3.0.1. 1. try 可以单独使用吗?
      2. 1.3.0.2. 2. 以下 try-catch 可以正常运行吗?
      3. 1.3.0.3. 3. 以下 try-finally 可以正常运行吗?
      4. 1.3.0.4. 4. 以下代码 catch 里也发生了异常,程序会怎么执行?
      5. 1.3.0.5. 5. 以下代码 finally 里也发生了异常,程序会怎么运行?
      6. 1.3.0.6. 6. 常见的运行时异常都有哪些?
      7. 1.3.0.7. 7. Exception 和 Error 有什么区别?
      8. 1.3.0.8. 8. throw 和 throws 的区别是什么?
      9. 1.3.0.9. 9. Integer.parseInt(null) 和 Double.parseDouble(null) 抛出的异常一样吗?为什么?
      10. 1.3.0.10. 10. NoClassDefFoundError 和 ClassNoFoundException 有什么区别?
      11. 1.3.0.11. 11. 使用 try-catch 为什么比较耗费性能?
      12. 1.3.0.12. 12. 常见的 OOM 原因有哪些?
      13. 1.3.0.13. 13. 以下程序的返回结果是?
      14. 1.3.0.14. 14. finally、finalize 的区别是什么?
      15. 1.3.0.15. 15. 为什么 finally 总能被执行?
  2. 1.4. 总结
|