1

异常

什么是异常

相异与常态,和正常情况下不一致,有错误出现。 阻止当前方法或作用域的,称为异常。

异常分类

clipboard.png

Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别。JDK中内建了一些常用的异常类,我们也可以自定义异常

Throwable又派生出Error类Exception类
  • Error

clipboard.png

错误: Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
  • Exception
Exception以及他的子类,代表程序运行的发生的各种不同不期望的事件,可以被java的异常处理机制所捕获,是异常处理的核心。

clipboard.png

clipboard.png

总体上我们根据Javac对异常的处理要求,将异常类分为2类。

一、非检查异常
Error和RuntimeException,以及她们的子类。javac在比那一的时候,不会提示和发现这样的异常,不要求用程序去处理这些异常,所以,最好的解决办法就是,我们应该是修正代码,而不是捕获异常处理,这样的异常多半是代码写的有误。

如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
二、检查异常
除了Error 和 RuntimeException的其它异常。javac强制要求对这类异常做预备处理(使用 try..catch..finally或者throws)。

在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。程序员就应该为这样的异常时刻准备着。

异常处理

try-catch

当遇到异常时,就会中断执行,然后程序的控制权将会移交catch中的异常处理程序

clipboard.png

  • try会抛出很多种类型的异常

clipboard.png

针对不同的异常,在不同的catch中处理,但是我们仍然需要注意一下: (先写子类后写父类)

clipboard.png

try-catch-finally

clipboard.png

实例

package tryCatchDemo;

public class Testdemo {
    
    public int test() {
        int initNum = 10;
        int result = 100;
        try {
            while(initNum > -1) {
                initNum --;
                result = result + 100/initNum;
            }
            return result;
        }catch(Exception e) {
            e.printStackTrace(); // 打印出错误
            System.out.println("循环异常");
            return -1;
        }
    }
}
package tryCatchDemo;

public class test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Testdemo t = new Testdemo();
        int result = t.test();
        System.out.println("抛出异常了,此时返回值为"+ result);
    }

}

clipboard.png

  • 修改一下
public int test1() {
        int initNum = 10;
        int result = 100;
        try {
            while(initNum > -1) {
                initNum --;
                result = result + 100/initNum;
            }
            return result;
        }catch(Exception e) {
            e.printStackTrace(); // 打印出错误
            System.out.println("循环异常");
            return -1;
        }finally{
            System.out.println("最终执行!!");
            return 999;
        }
    }

clipboard.png

  • 再修改一下
public int test2() {
        int initNum = 10;
        int result = 100;
        try {
            while(initNum > -1) {
                initNum --;
                result = result + 100/initNum;
            }
            return result;
        }catch(Exception e) {
            e.printStackTrace(); // 打印出错误
            System.out.println("循环异常");
            return result = 1000;
        }finally{
            System.out.println("最终执行!!");
            System.out.println("此时result的值为!!"+result);
        }
    }

clipboard.png

异常的抛出

  • throw 将产生的异常抛出(强调的是动作)
  • throws 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。

clipboard.png

实例

package throw_demo1;

public class newError {
    // 定义一个方法,抛出 数组越界和算术异常(多个异常 用 "," 隔开)
    public void Test1(int x) throws ArrayIndexOutOfBoundsException,ArithmeticException{

        System.out.println(x);
    
        if(x == 0){
    
            System.out.println("没有异常");
            return;
        }
    
        //数据越界异常
        else if (x == 1){
    
            int[] a = new int[3];
             a[3] = 5;
        }
    
        //算术异常
        else if (x == 2){
    
            int i = 0;
            int j = 5/0;
        }

    }
}
package throw_demo1;

public class test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //创建对象
        newError object = new newError();

        // 调用会抛出异常的方法,用try-catch块
        try{
            object.Test1(0);
        }catch(Exception e){
            System.out.println(e);
        }
        
        
        // 数组越界异常
        try{
            object.Test1(1);
        }catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界异常:"+e);
        }
        
        // 算术异常
        try{
            object.Test1(2);
        }catch(ArithmeticException e){
            System.out.println("算术异常:"+e);
        }

        //使用 throw 抛出异常(可以抛出异常对象,也可以抛出异常对象的引用)
        try{
            ArrayIndexOutOfBoundsException  exception = new ArrayIndexOutOfBoundsException();
            // 抛出异常
            throw exception;//new ArrayIndexOutOfBoundsException();

        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("thorw抛出异常:"+e);
        }
    }

}

clipboard.png

throw与throws的区别

1.  throw 在方法体内使用,throws 函数名后或者参数列表后方法体前
2.  throw 强调动作,而throws 表示一种倾向、可能但不一定实际发生
3.  throws 后面跟的是异常类,可以一个,可以多个,多个用逗号隔开。throw 后跟的是异常对象,或者异常对象的引用。 

自定义异常

class  自定义异常类 extends 异常类型(Exception){
// 因为父类已经把异常信息的操作都完成了,所在子类只要在构造时,将异常信息传递给父类通过super 语句即可。
// 重写 有参 和 无参  构造方法
}
// 一个DrunkException异常
package throwdemo2;

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

异常链

实例

// DrunkException.java
package throwdemo2;

public class DrunkException extends Exception{
    public DrunkException() {
        super();
    }
    public DrunkException(String msg) {
        super(msg);
    }
}
//test.java

package throwdemo2;

public class test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        test ct = new test();
        try {
            ct.test2();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    // 抛出一个异常
    public void test1() throws DrunkException{
        throw new DrunkException("你喝多了");
    }
    
    public void test2() {
        try {
            test1();
        }catch(DrunkException e) {
            // 捕获到test1的异常后,首先抛出一个运行时异常
            RuntimeException newErr = new RuntimeException("喝酒误事");
            // 设置该异常的造成原因为test1抛出的异常
            newErr.initCause(e); //=> 这里是异常链的关键
            // 抛出最后异常
            throw newErr;
            
            /**
             * 同样异常链还可以是
             * RuntimeException newErr = new RuntimeException(e);
             * throw newErr;
             */
            
        }
    }

}

clipboard.png

总结

1. 处理运行时异常时,采用逻辑去合理避免,同时配合try catch处理
2. 在多重catch之后,最好加上catch(Exception e)来处理可能会出现的异常
3. 对于不确定的代码,也可以加上try catch
4. 尽量去处理异常,切记只是简单的e.printStackTrace()去打印
5. 尽量添加finally语句去释放占用的资源

Meils
1.6k 声望157 粉丝

前端开发实践者