总的来说异常分为Error和Exception两大类
Exception又分为运行时异常和编译时异常
下面是常见的分类
小结:
public class test {
public static void main(String[] args) {
String name = null;
System.out.println(name.length());
}
}
public class test {
public static void main(String[] args) {
int n = 10;
int n1 = 0;
int n2 = n / n1;
}
}
public class test {
public static void main(String[] args) {
int [] arr ={1,2,3};
for (int i = 0; i <= arr.length; i++) {
System.out.println(arr[i]);
}
}
}
public class test {
public static void main(String[] args) {
A test = new B();
test = new C();
}
}
class A{}
class B extends A{};
class C extends A{};
public class test {
public static void main(String[] args) {
String name = "我不是数字";
int number = Integer.parseInt(name);//将指定的字符串转换为数字
//但是该字符串不能转换为数字
}
}
在try的代码区里是可能发生异常的代码,如果发生了异常,就会把其封装为Exception对象e传递给catch,我们在catch的代码区,可以增加自己的处理和业务逻辑(如输出异常信息等等),而最后无论是否发生了异常,都要执行finally代码区里面的代码,所以在里面写释放资源等一些必须要执行的代码
finally可以不写
对于第五点:
如果没有catch,相当于没有对异常做处理,就会把该异常往上throw,但是这还是会执行finally,如果往上throw,最后任然没有处理,程序就会在finally执行完后退出,报错
发生异常类似于continue,直接后面代码不执行,直接跳入catch
如果多个有异常,只要有一个异常发生,就会进入catch进行捕获,其后面的代码不执行,而catch可以有很多个,分别针对不同的异常,但是注意,把子类写在前面,父类写在后面,因为父类异常可以捕获其子类的异常
往调用它的对象throw,再去处理
如果没有try - catch,默认throw
class father{//父类
public void method() throws RuntimeException{
}
}
class son extends father{//子类
@Override
public void method() throws NullPointerException {
}//在子类继承父类的方法重写的时候
//抛出异常也有写出来,异常要是父类异常或其子类
}
对于在一个方法(假设叫f1),调用另一个方法(f2),f2抛出了异常,那此时在f1中我们要判断该异常是编译异常(图1)还是运行异常(图2),对于编译异常,要求我们必须处理(要么举行抛出,要么try-catch),而对于运行异常我们可以不做处理(但是最后可能还是要在处理)
throws:是直接在方法声明后面+系统有的异常类型
throw:因为异常的本质是一个类的,而我们手动抛出异常时,要抛出我们定义的这个类的对象(下面的抛出方式),而且是在方法体中抛出
public class test {
public static void main(String[] args) {
int age = 17;
if (!(age > 18 && age < 120)){
throw new AgeException("年龄应该处于18-120");
//直接抛出我们设置的异常,注意new
}
}
}
class AgeException extends RuntimeException{
public AgeException(String message) {
super(message);
}//本质上还是一个类,所以还是具有类的特点
}
题目
输出:4
分析:首先直接创建数组,默认成员为空(Null),而再调用equals时,会报空指针异常,所以直接到捕获空指针异常的代码块,但是因为最后finally一定要执行,所以最后要返回finally里面的值,就算是没有异常,也一定要执行finally,所以也是会返回其里面的值(可以理解为,只能返回一个,被最后的覆盖了)
题目
输出:4
分析:在上面一题我们知道,最后finally里的值一定是会返回的,但是空指针异常捕获里的++i也会执行,只不过不会直接返回值,但是里面的程序代码都会执行
题目
finally在t-c-f的处理当中永远是一定执行的,它的执行在抛出异常前面,比如在t-f当中也是,先执行finally后,再报错异常的
题目
输出:i = 4,返回3
分析:一样的异常处理逻辑,但是在捕获异常后,就可以返回值3,最后
还是要执行finally。
官方:在捕捉异常时,创基一个临时变量,把要返回的值赋给它,继续执行finally,最后返回临时变量里的值
public class test {
public static void main(String[] args) {
new test().way();
}
public void way(){
try {
System.out.println("请输入数字");
Scanner myScanner = new Scanner(System.in);
int number = Integer.parseInt(myScanner.next());
System.out.println(number);
} catch (NumberFormatException e) {
way();
}
}
}
方法二:
public class test {
public static void main(String[] args) {
System.out.println("请输入整数");
while (true){
Scanner myScanner = new Scanner(System.in);
try {
int number = Integer.parseInt(myScanner.next());
System.out.println("这个数是" + number);
break;
} catch (NumberFormatException e) {
System.out.println("输入错误,请输入整数");
}
}
}
}
需求:
自定义异常的实现:
根据继承父类,来确认是编译异常还是运行异常
案例:
设计一个异常,如果年龄不在18到120之间,就进行报错,提示年龄应该处于18-120
代码块实现:
public class test {
public static void main(String[] args) {
int age = 17;
if (!(age > 18 && age < 120)){
throw new AgeException("年龄应该处于18-120");
//直接抛出我们设置的异常,注意new
}
}
}
class AgeException extends RuntimeException{
public AgeException(String message) {
super(message);
}//本质上还是一个类,所以还是具有类的特点
}
当然这里我们设置的异常还是本质上是一个类,也可以有继承,接口,代码块,方法,属性,构造器(但是我们基本上只使用构造器)
首先,分为error和异常,对于异常我们有try-catch-finally和throws两种方式处理异常,而异常也具体的分为编译异常和运行异常
对于try-catch-finally,我们要了解它的处理与运行时的细节
一般是try,遇见异常,到catch里执行,再执行finally,再抛出异常
对于throws,我们要了解在抛出异常时的继承关系,和异常的类型