JAVA 异常机制

65 阅读3分钟

异常的体系结构

  • Error : Error指的是Java虚拟机无法去解决的严重问题,例如StackOverflowError和OOM
  • Exception :其它因编程错误或偶然的外在因素导致的一般性问题,例如角标越界、空指针异常

Exception的分类

image.png

编译时异常

是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子 类都是运行时异常。

运行时异常

是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。

异常处理方式

try-catch

try{
    // 代码
}catch(Exception e){
    //异常处理
}finally{
    //必定会执行的代码
}

案例 1:

public class ExceptionTest {
    public static void main(String[] args) {
        String str = "abc";
        try {
            Integer.parseInt(str);
        }catch (NumberFormatException e){
            System.out.println("在这里去处理异常......");
        }
        System.out.println("程序继续执行....");
    }
}

执行结果

image.png

案例2:

public class ExceptionTest {
    public static void main(String[] args) {
        String str = "abc";
        try {
            Integer.parseInt(str);
        }catch (NumberFormatException e){
            System.out.println("在这里去处理异常......");
        }catch (Exception e){
            System.out.println("使用Exception 处理");
        }
        System.out.println("程序继续执行....");
    }
}

image.png

案例3: image.png

小总结:

① 根据案例1和案例2可以看到,当我们处理完异常以后,代码会继续去执行他的流程

② 根据案例1和案例2可以看到,应该是先使用子类的异常进行处理,子类处理不了了,才会使用父类的异常进行处理。

③ 根据案例3可以看到,我们的异常定义的顺序应该是从小到大的

try-catch-finally

案例1:

@Test
public void testExceptionFinally(){
   int a = 10;
   int b = 0;

   try {
       System.out.println("a / b" + (a / b));
   }catch (ArithmeticException e){
       System.out.println("执行算数处理异常");
   }finally {
       System.out.println("执行finally");
   }
    System.out.println("程序继续执行");
}

执行结果:

image.png

案例2 :

    @Test
    public void testExceptionFinally(){
       int a = 10;
       int b = 0;

       try {
           System.out.println("a / b" + (a / b));
       }catch (ArithmeticException e){
           System.out.println("执行算数处理异常");
           try {
               String str = null;
               str.length();
           }catch (NullPointerException el){
               System.out.println("执行空指针异常");
           }
       }finally {
           System.out.println("执行finally");
       }
        System.out.println("程序继续执行");
    }
}

image.png

案例3:

    @Test
    public void testExceptionFinally(){
       int a = 10;
       int b = 0;
       try {
           System.out.println("a / b" + (a / b));
       }catch (ArithmeticException e){
           System.out.println("执行算数处理异常");
           String str = null;
           str.length();
       }finally {
           System.out.println("执行finally");
       }
        System.out.println("程序继续执行");
    }
}

image.png

案例4:测试有返回值的情况下

@Test
public void testMethod(){
    int method = method();
    System.out.println(method);
}
public int method(){
    try {
        int[] arr  = new int[10];
        System.out.println("arr[10]  =>" + arr[10]);
        return 1;
    }catch (IndexOutOfBoundsException e){
        System.out.println("执行角标越界异常");
        return 2;
    }finally {
        System.out.println("执行finally");
        return 3;
    }
}

执行结果:

image.png

小总结:

① 根据以上几个案例,我们可以知道如果写了finally它一定是会被执行的。

② 根据案例2和案例3,如果在catch中还有异常,如果没有做相关的处理会发现,会执行finally但是程序不会继续向下执行,如果做了处理,会继续向下执行

③根据案例4,可以看到,他在进行值返回的时候一定会先执行finally,然后在进行值的返回

④什么时候会用到finally,在释放数据库连接,IO连接,或者网络编程Socket的时候会使用到,也就是说Java虚拟机不能自动进行回收的,需要我们自己进行手动的资源释放

throws

   public void throwsTest() throws 要抛出的异常类型{
       //Code
   } 

小总结:

  • Throws 还是比较简单的,它只是将异常抛给别人,由别人来处理抛出的异常,它自己不做处理

throw手动抛出异常

可以抛出的异常必须是Throwable或其子类的实例

 throw new 异常类对象

用户自定义异常类

在一般情况下,自定义异常都是RuntimeException的子类,自定义异常需要提供serialVersionUID,自定义的异常通过throw抛出,重写相关的构造方法

public class MyException extends RuntimeException{
    static final long serialVersionUID = -7034897190745766939L;

    public MyException(){}
    public MyException(String msg){
        super(msg);
    }
}