异常处理机制


  • 抛出异常

  • 捕获异常

  • 异常处理的五个关键字

    • try:监控一个代码块,有异常就能通过catch捕获
    • catch(想要捕获的异常类型):捕获想要捕获的异常,catch代码块的代码只有在捕获到异常才执行
    • finally:处理善后工作。不管有没有捕获到异常,finally代码块的代码都会执行
    • throw用来抛出一个具体的异常类型(用在方法体中,使用throw一定会抛出一个异常)
    • throws用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁。(用在方法声明后面,表示可能会抛出异常,不一定会抛出)**

如何抛出和捕获异常


首先,我们来先看一个异常

public static void main(String[] args) {
        int a=1;
        int b=0;

        System.out.println(a/b);
    }

输出结果

Exception in thread "main" java.lang.ArithmeticException: / by zero

用try catch捕获这个异常

public static void main(String[] args) {
        int a = 1;
        int b = 0;

        try {
            System.out.println(a / b);
        } catch (ArithmeticException e) {
            System.out.println("程序出现异常:"+e);
        } finally {
            System.out.println("finally");
        }
    }

输出结果

程序出现异常:java.lang.ArithmeticException: / by zero
finally

接下来我们把b改为1试一下

public static void main(String[] args) {
        int a = 1;
        int b = 1;

        try {
            System.out.println(a / b);
        } catch (ArithmeticException e) {
            System.out.println("程序出现异常:" + e);
        } finally {
            System.out.println("finally");
        }
    }

输出结果:

1
finally
  • 可以发现如果没有捕获到异常,catch代码块是不会执行的,而finally代码块不管有没有捕获到异常都会执行。
  • 通常try和catch一起使用,finally可以不要,finally最常用在一些I/O流、资源类的使用后的关闭工作。

接下来,我们再看一个异常

public class Test {
    public static void main(String[] args) {       
        new Test().a();    
    }

    public void a(){
        b();
    }

    public void b(){
        a();
    }
}

输出结果

Exception in thread "main" java.lang.StackOverflowError

​ 因为a调b,b调a,程序陷入死循环,最终导致栈溢出了,接下来我们用上面的方式捕获异常

public class Test {
    public static void main(String[] args) {
        try {
            new Test().a();
        } catch (ArithmeticException e) {
            System.out.println("程序出现异常:" + e);
        } finally {
            System.out.println("finally");
        }
    }

    public void a(){
        b();
    }

    public void b(){
        a();
    }
}

输出结果

finally
Exception in thread "main" java.lang.StackOverflowError

可以发现没有捕获到异常,这是因为这个异常不是ArithmeticException,而是StackOverflowError,所以当然就捕获不到,接下来回顾一下异常类

我们知道了这是个栈溢出异常,要用StackOverflowError或者它的父类来捕获,假设我不知道它会抛出什么异常,我直接用异常的超类Throwable捕获也是可以的。

public class Test {
    public static void main(String[] args) {
        try {
            new Test().a();
        } catch (Throwable e) {
            System.out.println("程序出现异常:" + e);
        } finally {
            System.out.println("finally");
        }
    }

    public void a(){
        b();
    }

    public void b(){
        a();
    }
}

输出结果

程序出现异常:java.lang.StackOverflowError
finally

捕获多个异常


还是上面的例子,这次我们捕获多个异常,我们知道Error和Throwable都能捕获到异常

public class Test {
    public static void main(String[] args) {
        try {
            new Test().a();
        } catch (Exception e) {
            System.out.println("Exception捕获:" + e);
        } catch (Error e) {
            System.out.println("Error捕获:" + e);
        } catch (Throwable e) {
            System.out.println("Throwable捕获:" + e);
        } finally {
            System.out.println("finally");
        }
    }

    public void a() {
        b();
    }

    public void b() {
        a();
    }
}

输出结果:

Error捕获:java.lang.StackOverflowError
finally

​ 我们发现只被Error捕获,多个catch最终只有一个catch捕获到异常,接下来我们把Error和Throwable调换一下

public class Test {
    public static void main(String[] args) {
        try {
            new Test().a();
        } catch (Exception e) {
            System.out.println("Exception捕获:" + e);
        } catch (Throwable e) {
            System.out.println("Throwable捕获:" + e);
        } catch (Error e) {//编译报错了Exception 'java.lang.Error' has already been caught
            System.out.println("Error捕获:" + e);
        }  finally {
            System.out.println("finally");
        }
    }

    public void a() {
        b();
    }

    public void b() {
        a();
    }
}

​ 直接编译报错了Exception ‘java.lang.Error’ has already been caught,因为我们已经通过Throwable先捕获异常了,而Error是Throwable的子类,所以这个Error的catch永远不会被执行。因此捕获多个异常应该按从小(异常子类)到大(异常父类)的顺序捕获


快速捕获异常快捷键

  • 选中需要捕获异常的代码,ctrl+alt+t

throw主动抛出异常


我们程序中一些我们已经预知的异常,我们可以通过throw主动抛出

以第一个异常为例,我们都知道除数为0肯定是异常,我们就可以自己抛出

public static void main(String[] args) {
        int a=1;
        int b=0;
        try {
            if(b==0){
                throw new ArithmeticException("除数为0");//主动抛出异常
            }
            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }

输出结果

java.lang.ArithmeticException: 除数为0
	at com.dwy.exception.Test2.main(Test2.java:10)

throws抛出异常


我们写一个打印两个数相除的结果的方法

public class Test3 {
    public static void main(String[] args) {
        int a=1;
        int b=0;

        try {
            new Test3().printDivide(a,b);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } 
    }

    //打印两个数相除的结果
    public void printDivide(int a,int b) throws ArithmeticException{
        System.out.println(a/b);
    }
}

输出结果

java.lang.ArithmeticException: / by zero
	at com.dwy.exception.Test3.printDivide(Test3.java:17)
	at com.dwy.exception.Test3.main(Test3.java:9)

在printDivide函数捕获到异常时,会抛到调用该函数的方法中,在该方法中进行捕获处理。

遇到异常,就意味着你要进步了,这是一件好事。

狂神说java

版权声明:本文为dwystudy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/dwystudy/p/14772308.html