第7章 异常处理

第7章、异常处理

目录

  1. 一、异常概述与异常体系结构
  2. 二、常见异常
  3. 三、异常处理机制一:try - catch - finally (重点)
  4. 四、异常处理机制二:throws (重点)
  5. 五、手动抛出异常:throw
  6. 六、用户自定义异常类
  7. 面试题

一、异常概述与异常体系结构

异常概述

异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)

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

  • Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:java.lang.StackOverflowError(栈溢出)和java.lang.OutOfMemoryError(堆溢出,OOM)。一般不编写针对性的代码进行处理。
  • Exception(狭义异常): 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
    • 空指针访问
    • 试图读取不存在的文件
    • 网络连接中断
    • 数组角标越界
  1. 对于这些错误,一般有两种解决方法:一是遇到错误就终止程序的运行。另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。

异常体系结构

  • java.lang.Throwable
    • java.lang.Error
    • java.lang.Exception
      • 编译时异常(受检异常,checked)
        • IOException
          • FileNotFoundException
        • ClassNotFoundException
        • ...
      • 运行时异常(非受检异常,unchecked)java.lang.RuntimeException
        • NullPointerException
        • ArrayIndexOutOfBoundsException
        • ClassCastException
        • NumberFormatException
        • InputMismatchException
        • ArithmeticException
        • ...

二、常见异常

  • java.lang.RuntimeException
    • ClassCastException
    • ArrayIndexOutOfBoundsException
    • NullPointerException
    • ArithmeticException
    • NumberFormatException
    • InputMismatchException
    • 。。。
  • java.io.IOExeption
    • FileNotFoundException
    • EOFException
  • java.lang.ClassNotFoundException
  • java.lang.InterruptedException
  • java.io.FileNotFoundException
  • java.sql.SQLException

三、异常处理机制一:try - catch - finally(重点)

异常处理:抓抛模型

过程一:抛,程序在正常执行过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出。一旦抛出对象后,其后的代码就不再执行

过程二:抓,理解为异常处理方式:①try - catch - finally

try-catch-finally的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
try{
// 可能出现异常的代码
} catch(异常类型1 变量名1){
// 处理异常类型1的处理方式方式1
} catch(异常类型2 变量名2){
// 处理异常类型2的处理方式方式2
} catch(异常类型3 变量名3){
// 处理异常类型3的处理方式方式3
}
...
finally{
// 一定会执行的代码
}
  • 说明:
    • finally是可选的
    • 使用try将可能出现异常的代码包装起来,执行过程中一旦出现异常,就会生成一个异常类的对象,根据此对象的类型,去catch中进行匹配
    • 一旦try中的异常对象匹配到某个catch条件时,就进入catch中进行异常处理,一旦处理完成,就跳出当前的try-catch结构(无finally的情况),继续执行其后的代码
    • catch中的异常类型,如无子父类关系,谁声明在上、下无所谓;catch中的异常类型如满足子父类关系,则要求子类的catch语句声明在父类的catch语句上面,否则报错
    • 常用的异常对象处理方式:①String getMessage(); ②printStackTrace();
    • try结构中声明的变量,出了try结构后就不能被调用了
    • try-catch-finally结构可以嵌套
  • 体会
    • 使用try-catch-finally处理编译时异常,会使得程序在编译时不在报错,但在运行时可能会报错。相当于使用try-catch-finally结构将一个编译时可能出现的异常,延迟到运行时出现
    • 开发中,由于运行时异常比较常见,所以通常不针对运行时异常编写try-catch-finally了。但针对编译时异常,一定要考虑异常处理(处理编译时异常使得可能出现的异常延迟,起码生成字节码文件)

try-catch-finally中finally的使用

  1. finally是可选的
  2. finally中声明的是一定会被执行的代码,即使catch中又出现异常、try中有return语句(被执行)、catch中有return语句(被执行)等情况。【如try、catch、finally中都有return语句,则最终返回的是finally中的return语句】
  3. 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动回收的,我们需要手动进行资源的释放,此时的资源释放代码需要声明在finally中
  4. 右键 - surround with - try/catch block

四、异常处理机制二:throws(重点)

  1. “throws + 异常类型” 卸载方法的声明处,指明此方法执行时可能会抛出的异常类型。一旦方法体执行时出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后的异常类型时就会被抛出(抛给调用者),异常代码后的代码就不再执行
  2. 体会:
    • try-catch-finally:真正的把异常处理掉了
    • throws的方式只是将异常抛给了方法的调用者,并没有真正的将异常处理掉
  3. 开发中如何选择try-catch-finally,还是使用throws
    • 如父类中被重写方法没有throws处理异常,则子类重写的方法也不能使用throws方式处理异常,意味着如果子类重写的方法中有可能出现异常,必须使用try-catch-finally方式处理异常
    • 执行的方法a中,先后又调用了另外几个方法时,且这几个方法是递进关系执行的(下一个方法的执行依赖于上一个方法的正确结果),那么建议这几个方法使用throws方式进行处理,而执行的方法a可以考虑使用try-catch-finally方式进行处理

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

重写的方法,在编译时看的父类被重写方法,因此在编译阶段认为:方法抛出异常后调用者处理的是父类中被重写方法的异常类型,然而由于多态性,运行时运行的是子类重写的方法,因此如果子类重写的方法抛出的异常类型大于父类被重写的方法抛出的异常,调用者处理异常的方法失效,编译报错

五、手动抛出异常:throw

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

异常对象的产生:①系统自动生成的异常对象;②手动的生成一个异常对象,并抛出(throw)

六、用户自定义异常类

如何自定义异常类

  1. 继承于现有的异常结构:RuntimeException、Exception
  2. 提供全局常量serialVersionUID
  3. 提供重载的构造器

面试题

  1. 常见的异常都有哪些?举例说明
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
73
74
75
76
77
//******************以下是编译时异常***************************
@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();

}

//******************以下是运行时异常***************************
//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));

}
  1. throw和throws有什么区别?
    • throws为一种异常处理方式
      • 属于异常处理的一种方式,声明在方法的声明处
    • throw为手动抛出异常对象
      • 表示抛出一个异常类的对象,生成异常类对象的过程。声明在方法体内
  2. final、finally、finalize三者区别(
    • 结构相似的
      • Collection和Collections,
      • String、StringBuffer、StringBuilder,
      • ArrayList、LinkedList,
      • HashMap、LinkedHashMap,
      • 重写、重载
    • 结构不相似的
      • 抽象类、接口
      • ==、equals()
      • sleep()、wait()