1 异常机制
Throwable 类是 Java 语言中所有错误或异常的超类。
- 2个子类
-
Error:错误 严重错误,程序员无法解决
-
Exception:异常 ,是一种程序(代码)错误,程序员是可以解决的
(异常本身就是一个类)
异常机制的本质就是当程序出现错误,程序安全退出的机制
error是虚拟机崩溃,它是由JVM产生和抛出的,我们不需要管
2 RuntimeException运行时异常
代码执行过程中出现的异常,不需要throws异常
2.1 常见的运行时异常
- NullPointerException 空指针异常
- ArrayIndexOutOfBoundsException 数组下标越界异常
- ArithmeticException 算术运算异常
- InputMismatchException 类型匹配异常
- ClassCastException 类型转换异常
2.2 NullPointerException空指针异常
public class Test04 {
public static void main(String[] args) {
int[] arr = null;
System.out.println(arr.length);
}
}
2.3 ArithmeticException除0异常
public class Test04 {
public static void main(String[] args) {
int a = 0;
int b = 1;
System.out.println(b/a);
}
}
2.4 IndexOutOfBoundsException数组越界异常
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
2.5 ClassCastException异常
当对象转换为不属于实例的子类时发生(当强制转换很过分的时候)
public class Test04 {
public static void main(String[] args) {
Animal c = new Cat();
Animal d = new Dog();
c = (Cat)d;
}
}
class Animal{}
class Cat extends Animal{}
class Dog extends Animal{}
3 编译时异常
代码没有执行就报错,和语法错误没有关系
Exception及其子类(不包含运行时异常),统称为编译时异常,编译时异常可被检查出,要么用try——catch捕获异常要么就用throws声明异常。
比如IOException,编译时就要求抛出。
3.1 try-catch-finally(finally可省略)
try代码块中放可能出现异常的代码,表示尝试执行可能出现异常的代码
catch是对异常的捕获,
finally:表示最后一定会执行的意思
throws:表示声明可能会抛出
throw: 表示一定会抛出
try-catch-finally 机制中,catch可能会执行,finally的代码一定会执行,除非在try或catch中加System.exit(0);退出虚拟机操作
try-finally机制中,因为没有catch,没有捕获异常,所以默认是JVM抛出,finally只是为了释放资源。
try-catch一般不解决异常,只是为了不影响后面代码的运行
3.2 面试题:final,finalize,finally这三者区别?
-
final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
-
finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些**关闭资源**的代码。
-
finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System的gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾。
4 抛出异常(消极处理异常的方案)
4.1 throws
**编译时异常有两种处理方式:要么try……catch;要么抛出异常
throws:声明一个可能的异常,并把这个异常抛上一级,谁调用,谁处理.
- 如果将异常抛给上一级,一旦代码出现异常,则异常后面的代码不再执行;
4.2 throw
主动抛出一个异常对象,表示一定会出现异常
- 格式:出现在方法体中
- 注意1:throw后面不能出现代码
-
注意2:throw经常出现在catch中,将捕获的异常再次转义,抛一个更加友好或者范围更小的异常出去,有利于上级调用者处理异常
-
注意:如果异常发生地方有好几处,其实真正的异常一般只有一个,在最里面,也就是控制台报错的第一行
-
注意:如果异常一直向上声明抛出,最后会抛给JVM,那么我们的代码就无法正常执行了
-
注意:我们一般向外声明并且抛出的异常都是编译时异常
-
注意:一个方法可以向外声明多个异常,中间用逗号隔开
-
注意:可以向外声明编译时异常,也可以声明运行时异常
-
如果声明的是编译时异常,那么谁调用,谁必须处理(要么抛,要么try..catch..)
-
如果声明的是运行时异常,那么谁调用,谁处理
-
注意: 如果方法抛出的是父异常,那么上一级处理的时候,异常类型至少要>=抛出的异常
-
注意:如果一个方法抛出了多个异常,上一级处理的时候,可以将这些异常合并为1个异常(这些小异常必须是某一个大异常的子类)
-
注意:用户从前台传进来的数据,程序员需要对这些数据做验证处理
-
验证模式1:数据格式验证 前台做处理
-
验证模式2:数据(格式和准确性)验证 后台做处理
4.3 throws和throw的区别
- 格式
throws声明在方法头部
throw声明在方法体 - 异常抛出的几率不同
throws表示有可能会抛出异常
throw表示一定会抛出异常 - throws抛出的是异常类
throw抛出的是异常的对象 - 个数
throws可以抛出多个异常
throw只能抛出一个异常
System.err.println();打印的内容为红色字体。
5. 异常的一些其他的知识
子类声明异常的范围不能超过父类声明异常的范围
1. 父类没有声明异常,子类重写方法也不能声明异常,不是重写方法可以;
2. 父类如果抛出异常,子类只能抛出父类的异常或者该异常的子类
有时候我们会捕获一个异常,然后再抛出一个异常
// 自定义异常
class DenominatorZeroException extends Exception {
public DenominatorZeroException() {}
public DenominatorZeroException(String msg) {
super(msg);
}
}
// 计算器类
class Calculator {
// 除法运算
public static int division(int num, int den) throws DenominatorZeroException {
int result = 0;
try {
result = num/den;
}
catch(ArithmeticException e) {
// 抛出一个更详细的异常
throw new DenominatorZeroException("分母不能为0");
}
return result;
}
}
public class ExceptionTest07 {
public static void main(String[] args) {
try {
// 两个数做除法运算,可以会发生算数异常
Calculator.division(5, 0);
} catch (DenominatorZeroException e) {
e.printStackTrace();
}
}
}