异常与捕获

异常体系:

当程序出现错误时,能够最大化的减少损失的一种保护手段。
Java中异常也是类。

异常的继承类结构:

在这里插入图片描述

1、异常:

Error:Error类描述Java运行时内部错误与资源耗尽错误。应用程序不抛出此类异常,这种内部错误一旦出现,除了告知用户并使程序安全终止之外,别无他法。(例如:栈溢出异常(StackOverflowerror))
Exception:程序中普遍存在的,由于代码问题产生的错误。

  • IOException:程序本身没有问题,但由于出现输入输出问题导致的异常(例如:打开一个并不存在的文件)
  • RuntimeException:运行时异常,由于程序错误导致的异常(例如:数组越界异常、类型转换异常、空指针异常)

非受查异常:继承于Error与RuntimeException类的所有异常子类称为非受查异常(不强制用户进行异常处理)

受查异常:Exception与IOException子类属于受查异常(强制用户进行异常处理)

举例:

public class Test {

    public static void main(String[] args) {
        System.out.println("1、计算前:");
        System.out.println("2、计算中:" + 10 / 0);
        System.out.println("3、计算后:");
    }

}

在这里插入图片描述
可以看出,程序虽然出现了异常,但是产生异常之前的语句可以正常执行,而异常产生之后的程序直接结束,为了保证程序出现异常还可以继续向下执行,就需要异常处理。

2、异常处理格式:

try{
    //所有可能出现异常的语句
   }[catch (异常类 对象) ......]{
	//出现异常后捕获该异常,然后自定义处理方式
   }[finally]{
    //异常出口
    //保证重点代码(如IO流的关闭,JDBC资源的释放等)一定会被执行的机制
    //无论是否产生异常,均会执行finally代码块
    //即便try,catch,中存在return语句,也会在return之前执行finally代码块
   }

因为[ ]内的可以省略,所以共有三种格式:
try…catch…
try…finally…
try…catch…finally…

还是上面的代码,加上异常处理会是怎样的结果呢:

public class Test {

    public static void main(String[] args) {
        System.out.println("1、计算前:");
        try {
            System.out.println("2、计算中:" + 10 / 0);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("出现异常,除数有误!");
        }finally {
            System.out.println("4、finally代码块无论如何都会执行!");
        }
        System.out.println("3、计算后:");
    }

}

在这里插入图片描述

易考点:
问:下面的代码会输出啥?

public class Test {

    public static int test(int num){
        try{
            System.out.println(10/num);
            System.out.println("1、########");
            return 1;
        }catch (Exception e){
            System.out.println("2、++++++++");
            return 2;
        }finally {
            System.out.println("3、$$$$$$$$");
            return 3;
        }
    }
    public static void main(String[] args) {
        System.out.println(test(0));
    }

}

发生异常的时候,catch和finally块依然执行,最后返回的是finally块的内容:
在这里插入图片描述
正常情况下,try,finally块都会执行,最后返回的依然是finally块的内容:
在这里插入图片描述
这就说明,如果finally里存在return语句,即便try,catch,中存在return语句,也会在return之前执行finally代码块,而如果finally里没有return语句,才会执行try,catch里的return语句。
注意:finally只有一种情况不会执行

public class Test {
    
    public static void main(String[] args) {
        try{
            System.out.println("1、########");
            //系统退出(直接干掉JVM进程)
            System.exit(0);
        }catch (Exception e){
            System.out.println("2、++++++++");
        }finally {
            System.out.println("3、$$$$$$$$");
        }
    }

}

在这里插入图片描述

3、throws与throw

区别:
1、throws:用在方法声明上,明确表示此方法可能会产生异常但是方法内部不处理,将异常抛回给调用处。
2、throw:用在方法内部,表示人为进行异常对象的产生,一般与自定义异常类搭配使用。

4、RuntimeException类

public class Test {
    public static void main(String[] args) {
        String str = "100";
        int num = Integer.parseInt(str);
        System.out.println(num);
    }
}

上面这段代码在运行的时候很容易出现错误,如果你要包装的这个str不是全部由数字组成,就会出现数值转换异常,而在编写过程中并没有强制要求处理,属于非受查异常,像这样:

String str = "100a";

在这里插入图片描述
考点:解释Exception与RuntimeException的区别:
1、Exception是RuntimeException的父类,使用Exception定义的异常必须进行异常处理,属于受查异常;RuntimeException是运行时异常,属于非受查异常,可以由用户选择性的来进行异常处理。
2、常见的RuntimeException:空指针异常、类型转换异常、数组越界异常、除0异常
  最典型:ClassCastException(类型转换异常,用于向下转型时,如果子类对象没有进行向上转型,就不能向下转型),NullPointerException(空指针异常)

5、自定义异常类

只有Throwable及其子类才能被异常处理,如果自己定义一个其他的Exception肯定识别不了,要想让它被识别,就必须继承一个异常体系的父类:extends RuntimeException or Exception (一般用在架构设计时)

6、断言assert

断言是从JDK1.4开始引入的概念,断言是指当程序执行到某些语句之后其数据的内容一定是约定的内容。
语法:assert 布尔表达式:“返回false执行的代码块”
当断言返回false时会抛出断言异常。
Java断言开启参数(jvm参数)为-ea,默认断言关闭。

public class Test {
    public static void main(String[] args) {
        int num = 10;
        assert num == 55:"num应该为55!";
        System.out.println(num);
    }
}

在这里插入图片描述
考虑一个问题,从上面的代码可以看出,assert num == 55:"num应该为55!";这块可能会出现异常,那么可不可以使用try…catch…来捕获Exception呢?
很明显是不可以的,异常信息里显示这是一个Error,Exception和它同级,必须使用父类Throwable来接收这个异常。
在这里插入图片描述