Java(22)异常处理

异常处理

Java异常介绍

Java在程序执行过程中的不正常情况称为异常。捕获错误最理想时间是编译时候,但是有些错误在运行时才会报错。

Java程序运行过程中的异常主要分为两大类:

  1. Error:JVM系统内部错误、资源耗尽等情况。(程序员只能处理Exception,对Error无能为力。)
  2. Exception:编程错误等一般问题,如空指针访问、读取不存在的文件。。。
  • 异常案例1:数组越界异常
public class Test01{
    public static int [] intarr={2,3,5};
    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) { // i循环了0,1,2,3,但是数组长度只有3
            System.out.println(intarr[i]);
        }
    }
}
/*
编译时不报错,运行报错:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 
*/
  • 异常案例2:空指针访问异常
class Tennis{
    public int i=0;
}
public class Test01{
    public static void main(String[] args) {
        Tennis a=null; //a没有指向任何东西
        System.out.println(a.i); 
        //编译时不会报错,运行时报错:
        //Exception in thread "main" java.lang.NullPointerException
    }
}
  • 异常案例3:分母为0异常
public class Test01{
    public static int i=0;
    public static void main(String[] args) {
        float a=3/i;
    }
}
/*编译时不会报错,运行时报错:
Exception in thread "main" java.lang.ArithmeticException: / by zero
*/

Java异常类的层级

image-20200201032947712

运行异常是运行才能发现的异常,是我们的常见异常,上面举的3个例子都是运行异常。

异常处理机制

Java异常处理:抓抛模型(捕获或者抛出)。

捕获异常:

Java通过try...catch...finally捕获异常,语法格式如下:

try{
	//可能产生异常的代码
}catch (ExceptionName1 e1){ //catch可以有多个
	// 当产生ExceptionName1异常时执行措施
}catch (ExceptionName2 e2){
	// 当产生ExceptionName2异常时执行措施
}finally { //finally部分可写可不写
	//无条件执行语句,无论有没有异常都执行
}

案例1:

/**
 * 通过try...catch来捕获处理:
 * try{
 *     
 * }catch(){
 *     
 * }
 */
public class Test01{
    public static int i=0;
    public static void main(String[] args) {
        //用try花括号括住可能出错的代码
        try{   
            System.out.println(4/i); 
        }catch (Exception e){  //不知道捕获什么异常类时,可以使用异常的父类Exception
            System.out.println(e.getMessage()); //这行代码可以查看捕获的异常是什么
            e.printStackTrace();  //这行代码也可以查看捕获的异常是什么(打印方法调用栈)
            //catch(){}花括号里面可以不写任何内容
        }
        System.out.println("Kobe,this is for you");//这行不受上面是否报异常的影响,
    }
}
//运行结果为:Kobe,this is for you

案例2:

public class Test01{
    public static void main(String[] args) {
        String a=null;
        try{
            System.out.println(3/0);
            System.out.println(a.toString());
        }catch (java.lang.NullPointerException e1){
            System.out.println("捕获到了java.lang.NullPointerException异常");
        }catch (java.lang.ArithmeticException e2){
            System.out.println("捕获到了java.lang.ArithmeticException异常");
        }finally {
            System.out.println("emm");
        }
    }
}
/*运行结果为:
捕获到了java.lang.ArithmeticException异常
emm
*/
/*
从运行输出结果可知,程序并没有把两个异常都捕获到了,只捕获到了3/0产生的ArithmeticException异常,
这是因为捕获异常本身的目的就是为了防止程序出现异常,如果try{}花括号里面前面的内容出现异常,就不会执行后面的内容了,所以没有捕获到a.toString()的空指针异常。
*/
抛出异常:

使用方式:throws+try...catch

案例1:

package day01;

public class Test01 {
    public static void main(String[] args) {
        Flower a=new Flower();
        //调用fun1()时进行捕获异常:
        try{  
            a.fun1();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
class Flower{
    void fun1() throws Exception{  //已经知道会报错,抛出异常
        System.out.println(34/0);
    }
}

如果有抛出,某个上层调用就要有捕获处理。抛出异常,是当前方法不处理异常,但是把异常往上层的调用栈传递,由上层选择捕获异常进行处理,还是选择继续往更上层抛出。如果main()方法抛出异常,异常交由虚拟机JVM处理。

案例2:

package day01;

class Flower{
    static void fun1() throws Exception{  //异常从这里开始被抛出
        System.out.println(34/0);
    }
}
class Bee{
    static void fun2() throws Exception{  //fun1()被调用,但是异常没有被捕获处理,继续抛出
        Flower.fun1();
    }
}
public class Test01 {
    public static void main(String[] args) { //fun2()被调用,异常被捕获处理
        try{
            Bee.fun2();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
/*运行结果为:
java.lang.ArithmeticException: / by zero
	at day01.Flower.fun1(Test01.java:5)
	at day01.Bee.fun2(Test01.java:10)
	at day01.Test01.main(Test01.java:16)
*/
/*
Main调用fun2(),fun2()调用fun1()
printStackTrace()打印出了方法的调用栈,并给出了源代码的行号。
*/

案例3:如果异常被捕获并且继续抛出不同类型的异常(异常类型转换了),会发生什么?

package day01;

class Vege{
    static void fun1(String s){
        if(s==null){
            throw new NullPointerException();
        }else {
            System.out.println(s);
        }
    }
}
class Ora{
    static void fun2(){
        try{
            Vege.fun1(null);
        }catch (NullPointerException e1){
            throw new IllegalArgumentException();
        }
    }
}
class Test01{
    public static void main(String[] args) {
        try {
            Ora.fun2();
        }catch (IllegalArgumentException e2){
            e2.printStackTrace();
        }
    }
}
/*运行结果为:
java.util.NoSuchElementException
	at day01.Ora.fun2(Test01.java:22)
	at day01.Test01.main(Test01.java:29)
*/
/*
从运行结果可以看到,看不到原始的空指针异常的信息了,如果想要查看完整异常栈,需要添加参数,将本源代码的
第18行的throw new IllegalArgumentException();
改成throw new IllegalArgumentException(e1);
*/

在Java中已经可以捕获异常了,为什么还要抛出异常再进行捕获,这种机制有什么作用?个人目前理解是,为了使已经知道可能出现异常的方法继续用下去,把抓到的异常抛出给调用者,让调用者来处理。

异常的屏蔽:
package day01;

class Police{
    public static void main(String[] args) {
        try{
            System.out.println(4/0);
        }catch (Exception e1){
            throw new RuntimeException(e1);
        }finally {
            
        }
    }
}
/*此处进行了异常转型,运行结果为:
Exception in thread "main" java.lang.IllegalArgumentException
	at day01.Police.main(Test01.java:10)
*/

//----------------------如果finally也抛出异常:---------------
package day01;

class Police{
    public static void main(String[] args) {
        try{
            System.out.println(4/0);
        }catch (Exception e1){
            throw new RuntimeException(e1);
        }finally {
            throw new IllegalArgumentException();
        }
    }
}
/*运行结果为:
Exception in thread "main" java.lang.IllegalArgumentException
	at day01.Police.main(Test01.java:10)
*/

//从上面两段源代码运行结果可以知道,如果catch和finally同时准备抛出异常,catch的异常会被屏蔽不抛出
posted @ 2020-08-29 09:30  Whatever_It_Takes  阅读(251)  评论(0编辑  收藏  举报