Java基础——异常处理

异常,说起来,就是一张图,5个关键字。

一张图

Java基础——异常处理_第1张图片
image.png

5个关键字

  • try
  • catch
  • finally
  • throw
  • throws

Java的异常捕获机制是怎么处理异常的?
要出捕获,要么抛出


一、异常

异常是程序运行过程中出现的错误。
Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的父类。

异常主要分类两类,一类是 Error,另一类是 Exception
Exception有两个子类,一个是 RuntimeException,另一种是 非运行时异常,比如IOException。

接下来就说说说上面出现的这几个东西

  • Throwable
    异常和错误的爹,错的都是他

  • Error
    Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
    就好像,你走路走着走着,前方的路塌了,你能怎么办,无计可施。

  • Exception
    Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。

    • 运行时异常 RuntimeException
      运行时异常都是RuntimeException类及其子类。叫运行时异常嘛,运行时发生的异常,RuntimeException是我们程序开发中需要重点处理的异常
      如NullPointerException、 IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引 起的,程序应该从逻辑角度尽可能避免这类异常的发生。
  • 非运行时异常/检查性异常/检查异常/编译异常
    (非运行时异常,叫法有点多)
    一个异常,如果不是运行异常,那么他就是 非运行时异常。
    比如如IOException、SQLException等以及用户自定义的Exception异常。这些异常在编译时就会报错,我们必须处理,想不处理都不行。

二、5个关键字

Java异常处理涉及到五个关键字,分别是:try、catch、finally、throw、throws。

我们先来看一下

    try{       
        //(尝试运行的)程序代码     
        }catch(异常类型 异常的变量名){       
            //异常处理代码     
        }
        // finally 不是必须的
        finally{       
            //异常发生,方法返回之前,总是要执行的代码     
        }
    }

1、try

try语句块,表示要尝试运行代码,try语句块中代码受异常监控,其中代码发生异常时,会抛出异常对象。

2、catch

  • catch语句块会捕获try代码块中发生的异常并在其代码块中做异常处理,catch语句带一个Throwable类型的参数,表示可捕获异常类型。
  • 当 try中出现异常时,catch会捕获到发生的异常,并和自己的异常类型匹配,若匹配,则执行catch块中代码,并将catch块参数指向所抛的异常对象。
  • catch语句可以有多个,用来匹配多个中的一个异常,一旦匹配上后,就不再尝试匹配别的catch块了。

通过异常对象可以获取异常发生时完整的 JVM堆栈信息,以及异常信息和异常发生的原因等。

3、finally

finally语句块是紧跟catch语句后的语句块,这个语句块总是会在方法返回前执行,而不管是否try语句块是否发生异常

比如我们tr……catch IO输入输出的异常,那么我们可以在finally里面把流给关闭。

目的是给程序一个补救的机会。这样做也体现了Java语言的健壮性。

示例代码1 运行时异常
我们先来看一段代码,用0做除数,会抛异常

public class ThrowableTest {
    public static void main(String[] args) {    
        int a = 3;
        int b = 0;
        // 0如果做除数会抛异常
        System.out.println("result: "+a/b);
    }
}

运行抛会异常

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at TrowTest.ThrowableTest.main(ThrowableTest.java:8)

这里抛出的异常是运行时异常,在编译的时候不会出现。必须我们程序员自己在编码做预防处理,比如用异常捕获机制try……catch
.
.
示例代码2 异常捕获机制

public class ThrowableTest {
    public static void main(String[] args) {    
        int a = 3;
        int b = 0;
        try {
            // 0如果做除数会抛异常
            System.out.println("result: " + a / b);
        } catch (Exception e) {
            System.out.println("捕获到异常: " + e.toString());
        }
    }
}

运行结果:

捕获到异常: java.lang.ArithmeticException: / by zero

异常被我们捕获了,程序没奔溃,正常运行。

.
.

try,catch和finally的使用注意点

  • 1、try、catch、finally三个语句块均不能单独使用
    三者可以组成

    • try...catch...finally、
    • try...catch、
    • try...finally
      三种结构。

    catch语句可以有一个或多个,finally语句最多一个。

  • 2、try、catch、finally三个代码块中变量的作用域为代码块内部,分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。

  • 3、多个catch块时候,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,并且匹配catch语句的顺序是由上到下。

throws

throws表示什么

  • 当一个方法参数列表之后throws Exception,用来声明方法可能会抛出某些异常,那么调用该方法的地方就必须try……catch捕获异常,否则编译不通过。

throws什么时候用呢

  • 如果一个方法中某些代码有可能造成某种异常,但是并不确定怎么处置,那么这个方法应该声明抛出异常,表示该方法不对这些异常进行处理,有调用者进行着。

  • 如果调用者也无法处理这些异常,那么应该继续抛出throws,如果一层层往上throws,那么这个异常会最终达到main方法,到了main就终止了,JVM肯定会让你处理,这样编译就可以通过了。
    (如果你异常一致背向上抛到了main方法,你main方法从语法上其实也可以也throws Exception,da你是这么做就没意义了,跑出来干嘛,一点意思都没有了,一旦异常就奔溃了)

  • 当方法的调用者无力处理该异常的时候,应该继续抛出,而不是随随便便在catch块中打印一下堆栈信息做个勉强处理。当然,有能力处理的应该及时处理。

throw

throw关键字是用于方法体内部(语句抛出),用来抛出一个Throwable类型的异常。

  • 如果我们在方法里面的语句throw一个异常,那么分两种情况
    • 1、在方法内部对应 throw 异常的语句我们进行try……catch,那么异常就会在当前方法被处理,这没什么问题。
    • 2、在方法内部对应 throw 异常的语句我们没有进行try……catch,那么在当前方法我们用throws Exception,不然抛出这个异常没人接,就不好了。
      (只throw,不try……catch也不throws特可以,但是这样没意思一点)
  • 如果throw的是自定义异常,那么就必须 内部捕获异常 或者 throw Exception

.
.

示例代码 throws

public class Test {
    static String abc = null;
    public static void main(String[] args) {
        try {// 因为show() throws Exception,所以调用者 try……catch,不然编译不通过
            show(abc);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void show(String s) throws Exception{
        //这句代码会引发 java.lang.NullPointerException
        s.toString(); 
        
    }
}

输出

java.lang.NullPointerException
    at TrowTest.Test.show(Test.java:14)
    at TrowTest.Test.main(Test.java:7)

如上,我们在show方法 throws Exceptionthrows Exception了,所以调用者就艺try……catch
.
.

代理示例 throw 出 运行时异常

public class ThrowableTest {
    public static void main(String[] args) {
        int a = 3;
        int b = 0;
        System.out.println("result:  "+divisionNum(a, b));
    }
    
    private static  int divisionNum(int n1,int n2){
        try {
            if (n2 == 0) {
                throw new ArithmeticException("在方法内的语句 throw 抛出运行时异常");
            } 
        } catch (Exception e) {
            System.out.println("捕获异常  "+e.toString());
        }
        return n1/n2;
    }
}

运行结果,运行失败抛异常

Exception in thread "main" 捕获异常  java.lang.ArithmeticException: 在方法内的语句 throw 抛出运行时异常
java.lang.ArithmeticException: / by zero
    at TrowTest.ThrowableTest.divisionNum(ThrowableTest.java:18)
    at TrowTest.ThrowableTest.main(ThrowableTest.java:7)


.
.

自定义异常

ToMinException

public class ToMinException extends Exception {
    public ToMinException(String msg)  
    {  
        super(msg);  
    }  
}

.
.
ToMaxException

public class ToMaxException extends Exception {
    public ToMaxException(String msg)  
    {  
        super(msg);  
    }  
}

.
.
Test

public class Test {
    
    public static void main(String[] args) {
        Test test = new Test();
        try {
            test.simpleAdd10to20(8, 17);
        } catch (ToMinException e) {
            e.printStackTrace();
            System.out.println("捕获到的异常信息  toString()   :"+e.toString());
            System.out.println("捕获到的异常信息:getMessage()  "+e.getMessage());
        }catch(ToMaxException e){
            e.printStackTrace();
            System.out.println("捕获到的异常信息  toString()   :"+e.toString());
            System.out.println("捕获到的异常信息:getMessage()  "+e.getMessage());
        }
        
        //getMessage() //输出异常的信息 
        // printStackTrace() //输出导致异常更为详细的信息 
        
    }
    
    // 这个方法只允许大于10,和小于20的数字,我们违反规则的数抛异常(仅为演示)
    private int simpleAdd10to20(int a,int b) throws ToMinException,ToMaxException{
        if(a>10 || b>10){
            throw new ToMinException("不能有小于10 的参数");
        }
        
        if(a>20 || b>20){
            throw new ToMaxException("不能有大于20 的参数");
        }
        return a+b;
    }
}

输出:

TrowTest.ToMinException: 不能有小于10 的参数
    at TrowTest.Test.simpleAdd10to20(Test.java:27)
    at TrowTest.Test.main(Test.java:8)
捕获到的异常信息  toString()   :TrowTest.ToMinException: 不能有小于10 的参数
捕获到的异常信息:getMessage()  不能有小于10 的参数

以上演示完自定义异常了。

最后我们顺便说一下几个关于异常的方法:
e.printStackTrace();
是打印异常的堆栈信息,指明错误原因,其实当发生异常时,通常要处理异常,这是编程的好习惯,所以e.printStackTrace()可以方便你调试程序!

e.toString()
具体哪个异常类哪个方法,具体异常提示是什么

e.getMessage()
最简要的异常内容提示

你可能感兴趣的:(Java基础——异常处理)