Throwable类
Throwable类是整个异常体系类的父级类,它实现了Serializable接口,它的父类是Object类,它的子类有Exception和Error,这2个子类下面都有很多子类。
Error是程序发生了重大错误,不能解决,只能避免,比如:内存泄漏
Exception:可对其进行处理的异常
受检异常和非受检异常
受检异常(checkedException):程序必须处理该异常。除了RuntimeExcetion及其子类(运行时异常),其他的Exception及其子类都属于受检异常,这种异常的特点是java编译器会检查它,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
非受检异常(uncheckedException):编译器不要求强制处置的异常。包括运行时异常(RuntimeException与其子类)和错误(Error)。
运行时与非运行时异常
Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。
运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是非受检异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,不过一般情况下不自定义检查异常。
异常处理
程序运行过程中可能会出现异常情况,比如被0除、对负数计算平方根等,还有可能会出现致命的错误,比如内存不足,磁盘损坏无法读取文件等,对于异常和错误情况的处理,统称为异常处理。
Java异常处理主要通过5个关键字控制:try、catch、throw、throws和finally。try的意思是试试它所包含的代码段中是否会发生异常;而catch当有异常时抓住它,并进行相应的处理,使程序不受异常的影响而继续执行下去;throw是在程序中明确引发异常;throws的作用是如果一个方法可以引发异常,而它本身并不对该异常处理,那么它必须将这个异常抛给调用它的方法;finally是无论发不发生异常都要被执行的代码。
关键字:throw,throws,try和catch的用法如下:
throws出现在方法的声明中,表示该方法可能会抛出的异常,允许throws后面跟着多个异常类型
throw出现在方法体中,用于抛出异常。当方法在执行过程中遇到异常情况时,将异常信息封装为异常对象,然后throw。
try出现在方法体中,它自身是一个代码块,表示尝试执行代码块的语句。如果在执行过程中有某条语句抛出异常,那么代码块后面的语句将不被执行。一个try后面可以跟多个catch,但不管多少个,最多只会有一个catch块被执行。
catch出现在try代码块的后面,自身也是一个代码块,用于捕获异常try代码块中可能抛出的异常。catch关键字后面紧接着它能捕获的异常类型,所有异常类型的子类异常也能被捕获。
常见的异常:
NullPointerException 空指针异常
ArrayIndexOutOfBoundsException 数组下标越界异常
StringIndexOutOfBoundsException 字符串下标越界异常
ClassCastException 类型转换异常
NumberFormatException 数字转换异常
代码示例
下面来看看代码,从代码中深刻理解Exception
例1:
Scanner scanner = new Scanner(System.in);
// 下面可以引发InputMismatchException,为非受检异常
int i = scanner.nextInt();//这里定义为int,如果键盘输入为string类型则会出现异常
System.out.println(i);
// 下面这个是受检异常,必须处理,否则编译不通过
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
例2:
int i;
Scanner scanner = new Scanner(System.in);
try {// 放可能发生异常的代码块
i = scanner.nextInt();
} catch (InputMismatchException e) {
System.out.println("捕获到了InputMismatchException");
} catch (Exception e) {// 捕获异常,对异常的处理
System.out.println("发生了异常");
e.printStackTrace();
} finally {// 始终要执行的代码
System.out.println("无论有没有发生异常我是一定会执行的");
}
System.out.println("----程序结束");
将上面的代码运行2次输出结果分别是:
第一次输入123结果
123
无论有没有发生异常我是一定会执行的
----程序结束
第二次输入asdf结果
asdf
捕获到了InputMismatchException
无论有没有发生异常我是一定会执行的
----程序结束
由这2次结果可以看出,finally不能是否发生异常都执行了;try后面可以跟着多个catch,但是最多只能执行一个catch。可以在try后面加任意数量的catch块,如果try中的代码发生异常,异常被抛给第一个catch快,如果抛出异常的数据类型与第一个catch类型匹配,它就在这里被捕获,如果不匹配,它会传入第二个catch块,以此类推知道最后一个catch块。
例3:
public static void main(String[] args) {
int a = 10, b = -4;
int result;
try {
result = div(a, b);
System.out.println("result=" + result);
} catch (Exception e) {
System.out.println("捕获到了异常");
System.out.println(e.getMessage());
}
System.out.println("---程序结束");
}
// 在方法后面用throws关键字 把异常抛出去,谁调用谁处理
public static int div(int a, int b) throws Exception {
if (b < 0) {
// 使用throw抛出一个异常
throw new Exception("被除数不能小于0");
}
if (b == 0) {
// 使用throw抛出一个异常
throw new Exception("被除数不能为0");
}
return a / b;
}
输出为:
捕获到了异常
被除数不能小于0
---程序结束
这个例子是自定义什么条件下抛出异常,我们定义了被除数为0或者被除数小于0时抛出异常,并通过throws把异常抛出,谁调用这个方法,谁就处理这个异常或者继续抛出。
扩展:错误和异常的区别(Error vs Exception)
1)java.lang.Error:Throwable的子类,用于标记严重错误。合理的应用程序不应该去try/catch这种错误。绝大多数的错误都是非正常的,就根本不该出现的。
2)java.lang.Exception: Throwable的子类,用于指示一种合理的程序想去catch的条件。即它仅仅是一种程序运行条件,而非严重错误,并且鼓励用户程序去catch它。
扩展:错误和异常的区别(Error vs Exception)
1)java.lang.Error: Throwable的子类,用于标记严重错误。合理的应用程序不应该去try/catch这种错误。绝大多数的错误都是非正常的,就根本不该出现的。
2)java.lang.Exception: Throwable的子类,用于指示一种合理的程序想去catch的条件。即它仅仅是一种程序运行条件,而非严重错误,并且鼓励用户程序去catch它。
声明自定义异常
在java中可以自定义异常,编写自己自定义的异常时需要注意:
- 所有异常都必须是Throwable的子类
- 如果希望写一个受检异常类,则需要继承Exception类
- 如果希望写一个运行时异常类,那么需要继承RuntimeException类
请尊重作者劳动成果,转载请标明原文链接:https://www.jianshu.com/p/aaf0103604d8