什么是异常

异常通常指方法在不能正常运行的时候,通过抛出异常的方式退出方法。

异常的分类

image.png

  • Throwable是所有错误和异常的父类。
  • Error通常是系统错误,或者资源耗尽,如果出现Error,系统就会终止运行,停止工作,常见Error有OutOfMemory(内存溢出),ThreadDeath(线程死锁)等等
  • Exception又被分为两种,一是运行时异常(RunTimeException),而是检查异常(CheckedException)。

运行时异常:指Java虚拟机在运行期间抛出的异常,这种程序发生错误抛出的异常,我们通常是捕获处理异常,或者抛出异常。常见的运行时异常有NullPointerException(空指针异常),ClassCastException(类型转换异常),ArrayIndexOutOfBundsException(数组越界异常)等等。
检查异常:指在编译阶段Java编译器会检查CheckedException异常,并强制程序处理此异常,否则无法通过编译。常见的检查异常有SQLException(SQL异常),IOException(IO异常),ClassNotFoundException(文件未找到)等等。
**

处理异常

处理异常有两种方式,一是用try,catch语句块来处理,二是抛出异常。

  1. try,catch

使用try,catch捕获异常更有针对性,我们只需要可能出现异常的代码,放在try语句块里面,就能捕获可能出现的异常,然后在catch语句块里面做相应的处理即可。

  1. public static void main(String[] args) {
  2. int a = 1;
  3. int b = 0;
  4. try {
  5. int c = a / b;
  6. } catch (Exception e) {
  7. //捕获异常并处理
  8. }
  9. }

**

  1. 抛出异常

抛出异常也分两种,一是方法内部抛出异常,二是方法上抛出异常。

  • 使用throw关键字在方法内部抛出异常

    throw 抛出异常后面代码不会执行(finally内的代码除外)

  1. public static void main(String[] args) {
  2. String[] arr = new String[3];
  3. int a = 3;
  4. if (a > 2){//抛出异常
  5. throw new ArrayIndexOutOfBoundsException();
  6. }else {
  7. String b = arr[a];
  8. }
  9. }
  • 使用throws关键字在方法上抛出异常

    当前方法可能会抛出异常,但是不知道如何处理该异常,就将该异常交由调用这个方法的的上一级使用者处理,如果上一级也不知道如何处理这个异常的时候,就会交由JVM来处理这个异常,JVM的做法是:打印异常的跟踪栈消息,并终止程序。

  1. public int div(int a, int b) throws Exception{
  2. return a/b;
  3. }

创建自定义异常

当Java中自带的所有异常不能满足我们的异常错误时,我们可以自定异常来处理。
自定义异常时,继承Exception,使用父类的构造器。

  1. public class MyException extends Exception{
  2. public MyException(){
  3. super();
  4. }
  5. public MyException(String msg){
  6. super(msg);
  7. }
  8. }

例如:如果数组中赋值时,有重复元素时,抛出自定义异常。

  1. public static void main(String[] args) throws MyException {
  2. int[] arr = new int[3];
  3. arr[0] = 1;
  4. arr[1] = 2;
  5. int b = 1;
  6. for (int i = 0; i < arr.length; i++) {
  7. if (arr[i] == b){
  8. throw new MyException("数组中已存在元素"+b);
  9. }else {
  10. arr[2] = b;
  11. }
  12. }
  13. }

image.png

finally关键字

finally关键字必须和try,catch一起使用,只有在try代码块得到执行的情况下,finally代码块才会得到执行。

  1. public class test1{
  2. public static void main(String[] args) {
  3. System.out.println(test());
  4. }
  5. public static int test() {
  6. String[] arr = new String[1];
  7. System.out.println(arr[2]);
  8. try {
  9. System.out.println("执行try");
  10. return 0;
  11. } catch (Exception e) {
  12. System.out.println("执行catch");
  13. return 0;
  14. } finally {
  15. System.out.println("执行finally");
  16. }
  17. }
  18. }

image.png
举个例子,上述代码中,在输出arr[2]就报错了ArrayIndexOutOfBoundsException,下标越界。try中的代码没执行,所以finally中的代码也没有执行。

  1. public class demo {
  2. public static void main(String[] args) {
  3. int a = 1;
  4. System.out.println(test(a));
  5. }
  6. public static int test(int a){
  7. int b = 2;
  8. try {
  9. a = b;
  10. return a;
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. finally {
  15. System.out.println("执行finally");
  16. a =3;
  17. }
  18. return a;
  19. }
  20. }

image.png
我们看到finally语句块内的代码执行了输出,我们在finally中将a赋值为3,但是为什么返回a 确实等于2呢。
当在执行test方法时,a =b并没有发生异常,此时已经将结果存在了return语句中,本来要结束方法时,发现还有finally代码块没执行,执行finally中的代码,虽然将a赋值成3,但是return中存的结果值是2,所以返回的2。