异常介绍

异常分为Error和Exception两种类型。

Error

Error是Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。

Exception

Exception是因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。

Exception又可分为Check Exception和Uncheck Exception

Check Exception

编译时出现的异常

  1. SQLException

    操作数据库时,查询表可能发生的异常

  2. IOException

    操作文件时发生的异常

  3. FileNotFoundException

    当操作一个不存在的文件时发生的异常

  4. ClassNotFoundException

    加载一个不存在的类时发生的异常

  5. EOFException

    操作文件到文件末尾时发生的异常

  6. IllegalArgumentException

    参数异常

Uncheck Exception

运行时出现的异常

  1. NullPointerException 空指针异常

    1
    2
    String name = null;
    System.out.println("name.length");
  2. ArithmeticException 数学运算异常

    1
    System.out.println(1/0);
  3. ArrayIndexOutOfBoundsException 数组下标越界异常

    1
    2
    int[] arr = {1,6,8};
    System.out.println(arr[3]);
  4. ClassCastException 类型转换异常

    1
    2
    3
    4
    5
    6
    A b1 = new B(); //向上转型
    B b2 = (B)b1; //向下转型
    C c1 = (C)b; //抛出异常
    class A{}
    class B extends A{}
    class C extends A{}
  5. NumberFormatException 数字格式异常

    1
    String name2 = "www"; System.out.println(Integer.parseInt(name2));

基本语法

IDEA快捷键:Ctrl + Alt + T

try-catch-finally

程序员在代码中捕获发生的异常,自行处理

1
2
3
4
5
6
7
8
9
try{
可能有异常的代码块
} catch (异常类型 异常对象名) {
捕获到异常后要执行的代码块
} catch (异常类型 异常对象名) {
捕获到异常后要执行的代码块
} finally {
无论有无异常都要执行的代码块,可以关闭连接、释放资源等
}

处理机制:

  1. 当异常发生时,异常代码后面的代码不再执行
  2. 系统将异常封装成Exception对象e,传递给catch
  3. 得到异常对象后,程序员自行处理
  4. 如果没有发生异常,catch代码块不执行

注意:

  1. 存在try-finally方式,不处理异常,程序会直接崩溃
  2. 存在多个catch用于处理不同的业务逻辑。但是子类异常要写在前面,父类异常写在后面。

小练习:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num;
System.out.print("请输入一个整数:");
while(true){
try {
num = Integer.parseInt(sc.next());
break;
} catch (NumberFormatException e) {
System.out.print("你输入的不是整数,请重新输入:");
}
}
System.out.println("你输入的整数是:"+num);
}

throws

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

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

处理机制:

从最底层一层层往上throws

1
2
3
4
5
6
7
8
9
public static void f1(){
f2(); //不会报错,因为f2()抛出的运行异常,有默认处理机制
f3(); //报错,因为f3()抛出的编译异常,f1()必须要处理这个异常
}
public static void f2() throws RuntimeException{
}
public static void f3() throws IOException{

}

自定义异常

应用实例

当我们接受Person对象年龄时,要求范围在18-120之间,否则抛出一个自定义异常(要求继承RuntimeException)并给出提示信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CustomException {
public static void main(String[] args) {
int age = 220;
if (!(age >= 80 && age <= 120)) {
throw new AgeException();
}
System.out.println("你的年龄在18-120之间");
}
}
class AgeException extends RuntimeException {
public AgeException() {
super("你的年龄输入有误!");
//通过构造器,设置异常信息
}
}

一般情况下,自定义异常是继承RuntimeException即把自定义异常做成运行时异常,可以使用默认的处理机制,比较方便

throw和throws

意义 位置 后面跟
throws 异常处理的一种方式 方法声明处 异常类型
throw 手动生成异常对象的关键字 方法体中 异常对象

加深理解

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
public class Important {
public static void main(String[] args) {
try {
ReturnExceptionDemo.methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
}
ReturnExceptionDemo.methodB();
}
}

class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally {
System.out.println("用A方法的finally");
}
}

static void methodB() {
try {
System.out.println("进入方法B");
return;
} finally {
System.out.println("调用B方法的finally");
}
}
}

输出结果是:

1
2
3
4
5
进入方法A
用A方法的finally
制造异常
进入方法B
调用B方法的finally

IDEA格式化代码快捷键:Ctrl + Alt + Shift + L