JAVA学习笔记Ⅶ——异常与异常处理

异常简介

什么是异常

异常:有异于常态,和正常情况不一样,有错误出现。阻止当前方法或作用域继续执行的问题,称之为异常。【说白了从广义上讲就是程序的运行与预期不符】

               

当程序出现异常的时候,就会得不到正常的运行以至于不正常退出,严重情况会造成数据的丢失,程序运行所占用的资源得不到有效释放

处理异常的作用与意义

对于异常的正确处理能够将异常提示给编程人员或者用户,使本来已经中断了的程序以适当的方式继续运行或者是退出,并且能够保存用户的当前操作或进行数据回滚,最后释放占用资源

运行时异常(RuntimeException)会由JAVA虚拟机自动抛出,并自动捕获,运行时异常的出现,绝大部分情况说明了代码本身有问题,应该重逻辑上改进代码。检查异常(CheckException)需要手动添加捕获以及处理语句

一般ERROR出现就表明程序彻底挂了,而Exception出现还能抢救一下

Throwable 部分结构
Throwable
ERROR
Exception
虚拟机错误
VirtualMachineError
线程死锁
ThreadDeath
非检查异常
RuntimeException
检查异常
CheckException
空指针异常
NullPointerException
数组下标越界异常
ArrayIndexOutOfBoundsException
类型转换异常
ClassCastException
算术异常
ArithmeticException
文件异常
IOException
SQL异常
SQLException

处理异常

try-catch以及try-catch-finally,其作用分别对标Python中的try-except以及try-except-finally,如果try中的代码出现异常,会把程序控制权交由catch语句块,最终会运行finally语句块【如果存在finally语句块】。

结构如下,对于catch捕捉异常的方式采用就近原则【因为子类继承于父类,针对于父类的异常程序对于子类也是适用的】,所以应该先子类后父类进行编写【编译器对于catch的编写会自动检查,对于错误的顺序会进行提示,所以无需慌促】。

try{
	//一些会抛出异常的方法
} catch (Exception1 e){
	//处理该异常的代码块
} catch (Exception2 e){
	//处理该异常的代码块
}...(n个catch)...{
} finally {
	//最终将要执行的一些代码
}

Main.java

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.println("请输入你的年龄:");
            int age = input.nextInt();
            System.out.println("十年后你" + (age + 10) + "岁");

            System.out.println("请输入除数:");
            int num = input.nextInt();
            System.out.println("年龄是" + num + (age / num) + "倍");

        }catch (InputMismatchException e){
            System.out.println("你应该输入整数");
            e.printStackTrace();
        }catch (ArithmeticException e){
            System.out.println("除数不能为0");
            e.printStackTrace();
        }catch (Exception e){
            System.out.println("Unkonwn Error!");
            e.printStackTrace();
        }
        finally {
            System.out.println("程序结束!");
        }
    }
}

TryCatchTest.java

package com.template22;

public class TryCatchTest {
    public static void main(String[] args) {
        TryCatchTest tct = new TryCatchTest();
        int result = tct.test();
        System.out.println("test方法,执行完毕!返回值为:" + result);
        int result2 = tct.test2();
        System.out.println("test2方法,执行完毕!返回值为:" + result2);
        int result3 = tct.test3();
        System.out.println("test3方法,执行完毕!返回值为:" + result3);
    }

    /*
     *divider(除数):
     *result(结果):
     *try-catch捕获while循环
     *每次循环,divider减一,result=result+100/divider
     *如果:捕获异常,打印输出“抛出异常了!!!”,返回-1
     */
    public int test(){
        int divider = 10;
        int result = 100;
        try{
            while(divider > -1){
                divider--;
                result = result + 100/divider;
            }
            return result;
        } catch (Exception e){
            //输出异常以及异常抛出的位置
            e.printStackTrace();
            System.out.println("循环抛出异常了!!!");
            return -1;
        }
    }

    /*
     *divider(除数):
     *result(结果):
     *try-catch捕获while循环
     *每次循环,divider减一,result=result+100/divider
     *如果:捕获异常,打印输出“抛出异常了!!!”,返回 result=999
     * finally:打印输出“finally执行完毕了!!!”
     */
    public int test2(){
        int divider = 10;
        int result = 100;
        try{
            while(divider > -1){
                divider--;
                result = result + 100/divider;
            }
            return result;
        } catch (Exception e){
            //输出异常以及异常抛出的位置
            e.printStackTrace();
            System.out.println("循环抛出异常了!!!");
            return result = 999;
        } finally {
            System.out.println("finally执行完毕了!!!result值为" + result);
        }
    }

    /*
     *divider(除数):
     *result(结果):
     *try-catch捕获while循环
     *每次循环,divider减一,result=result+100/divider
     *如果:捕获异常,打印输出“抛出异常了!!!”
     * finally:打印输出“finally执行完毕了!!!”
     * 最后,返回1111作为结果
     */
    public int test3(){
        int divider = 10;
        int result = 100;
        try{
            while(divider > -1){
                divider--;
                result = result + 100/divider;
            }
        } catch (Exception e){
            //输出异常以及异常抛出的位置
            e.printStackTrace();
            System.out.println("循环抛出异常了!!!");
        } finally {
            System.out.println("finally执行完毕了!!!result值为" + result);
        }
        System.out.println("test3运行完毕!");
            return 1111;
    }
}

TryCatchTest.java中的test2方法中,在执行完catch语句块的return赋值语句后,并不会马上返回至main方法,而是执行完finally语句块后返回至main方法。在TryCatchTest.java中的test3方法中,如果整个try-except-finally都没有return返回值语句,将执行语句块外的return语句【如果语句块外存在return语句】

JAVA中的异常抛出

JAVA 异常类库

虽然JAVA标准类库中提供了丰富的异常种类,但是在实际应用情景中也难免用到JAVA类库中没有的异常,因此我们需要使用自定义异常

自定义异常

自定义异常是自己定义的异常,它必须继承于JAVA标准类库中意思相近的异常类型,或者直接继承所有异常类的基类,也就是Exception类型。

throw throws
将产生的异常抛出(动作),写在方法体内部,表示具体抛出异常的动作 声明将要抛出何种类型的异常(声明)
public void 方法名(参数列表)throws 异常列表{
    //调用会抛出异常的方法或者:throw new Exception();
}
throws 可以抛出多种异常类型,每种异常类型用逗号(,)隔开

如果某个方法调用到了会抛出异常的方法,那么必须添加try-catch语句去尝试捕获这种异常,或者添加throws声明,来将异常的抛出给更上一层的调用者进行处理

可处理异常 抛出异常 不能处理异常
通过try-catch捕获并处理异常
public void compute(){
    /*
    *此处省略…代码…
    **/
    try{
        divide(5, 0);
    } catch (Exception e){
        System.out.println(e.getMessage());
    }
}
public void divide(int one, int two) throws Exception{
    if two==0)
        throw new Exception(“两数相除,除数不能为0!!”);
    else
        System.out.println(“两数相除,结果为:”+one/two);
}
不能处理异常,将异常声明抛出,给更上一层调用者去处理
public void compute() throws Exception{
    /*
    *此处省略…代码…
    **/
    divide(5, 0);
}
class 自定义异常类 extends 异常类型{
 //类体
}

自定义一个DrunkException异常

DrunkException.java

package com.template22;

public class DrunkException extends Exception{

    public DrunkException(){

    }

    public DrunkException(String message){
        super(message);
    }
}

异常链

JAVA中的异常链:将捕获的异常包装成一个新的异常,在新的异常里添加对原始异常的引用,再把新异常抛出,就如同链式反应一样,一个导致另一个。

定义ChainTest.java实现异常链,需要用到前面自定义的DrunkException这个类,这是自定义的一个异常

ChainTest.java

package com.template22;

public class ChainTest {

    /**
     * test1():抛出“喝大了”异常
     * test2():调用test1(),捕获“喝大了”异常,并且包装成运行时异常,继续抛出
     * main方法中,调用test2(),尝试捕获test2()方法抛出的异常
     */
    public static void main(String[] args){
        ChainTest ct = new ChainTest();
        try{
            ct.test2();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public void test1() throws DrunkException{
        throw new DrunkException("喝酒别开车");
    }

    public void test2(){
        try{
            test1();
        } catch (DrunkException e){
//            RuntimeException newExc = new RuntimeException("司机一滴酒,情人两行泪");
//            newExc.initCause(e);
//            throw newExc;

            throw new RuntimeException(e);
        }
    }
}

java.lang.RuntimeException: com.template22.DrunkException: 喝酒别开车
	at com.template22.ChainTest.test2(ChainTest.java:31)
	at com.template22.ChainTest.main(ChainTest.java:13)
Caused by: com.template22.DrunkException: 喝酒别开车
	at com.template22.ChainTest.test1(ChainTest.java:20)
	at com.template22.ChainTest.test2(ChainTest.java:25)
	... 1 more

在代码中,我们首先自定义了一个异常DrunkException【喝大了异常】,在ChainTest.java中,我们先定义了一个test1()方法用于抛出定义的异常,我们定义了一个test2()方法使用try-catch来捕获test1()抛出的异常,并将这个异常包装成了一个新的异常RuntimeException【运行时异常】并抛出,在main方法中调用test2(),尝试捕获test2()方法抛出的异常。

经验总结

1.处理运行时异常可以采用优化代码,采用逻辑加以控制去合理规避的同时辅助加上try-catch进行处理
2.在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
3.对于不确定的代码,也可以加上try-catch,处理潜在的异常
4.尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
5.具体如何处理异常,需要根据不同的业务需求和异常类型去决定
6.尽量添加finally语句块去释放占用资源,尤其是有网络连接和连接数据库的情况

猜你喜欢

转载自blog.csdn.net/qq_39567427/article/details/107457163