【JAVA系列】关于异常的一些事


前言

JAVA提供强大的异常处理机制,在Java中,所有的异常都会被封装到一个类中,程序出错时会将异常抛出。


一、如何知道程序错误

代码中的错误是客观存在的,没有十全十美的代码,代码多到一定程序,我们就需要不断维护、检查代码的错误,确保健壮性。

在Java中,我们有以下两种方式告诉程序代码发生错误:

  1. LBYL: Look Before You Leap. 在操作之前就做充分的检查
  2. EAFP: It’s Easier to Ask Forgiveness than Permission. “事后获取原谅比事前获取许可更容易”. 也就是先操作, 遇到问题再处理.

简单来说就是第一种没有使用异常,第二采用了异常的方法

代码风格如下:

LBYL: Look Before You Leap. 在操作之前就做充分的检查:

boolean ret = false;
ret = 登陆游戏();
if (!ret) {
 处理登陆游戏错误;
    return; }
ret = 开始匹配();
if (!ret) {
 处理匹配错误;
    return; }
ret = 游戏确认();
if (!ret) {
 处理游戏确认错误;
    return; }ret = 选择英雄();
if (!ret) {
    处理选择英雄错误;
    return; }
ret = 载入游戏画面();
if (!ret) {
 处理载入游戏错误;
    return; }
......

It’s Easier to Ask Forgiveness than Permission. “事后获取原谅比事前获取许可更容易”. 也就是先操作, 遇到问题再处理:

try {
    登陆游戏();
    开始匹配();
    游戏确认();
    选择英雄();
    载入游戏画面();
   ...
} catch (登陆游戏异常) {
    处理登陆游戏异常;
} catch (开始匹配异常) {
 处理开始匹配异常;
} catch (游戏确认异常) {
 处理游戏确认异常;
} catch (选择英雄异常) {
 处理选择英雄异常;
} catch (载入游戏画面异常) {
 处理载入游戏画面异常; }
.....

对比两种不同风格的代码, 我们可以发现:

使用第一种方式, 正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱.

而第二种方式正常流程和错误流程是分离开的, 更容易理解代码

二、常见的异常

所谓异常指的就是程序在 运行时出现错误时通知调用者的一种机制

异常的种类有很多, 不同种类的异常具有不同的含义, 也有不同的处理方式,下面介绍几种常见异常:

1.算术异常

public static void main(String[] args) {
        //1.算术异常
        System.out.println(10/0);
    }

在这里插入图片描述

2.数组越界异常

public static void main(String[] args) {
        int []arr=new int[4];
        System.out.println(arr[10]);
    }

在这里插入图片描述

3.空指针异常

public static void main(String[] args) {
        String str=null;
        System.out.println(str.length());
    }

在这里插入图片描述

二、异常的基本用法

1.如何捕获异常

异常处理是由try、catch与finally等3个关键字组成的程序块。
其异常的基本语法:

try{
		要检查的程序语句;
		...
		}
catch(异常类 对象名称){
		异常发生时的处理语句;
		}
[
catch(异常类 对象名称){
		异常发生时的处理语句;
		}
catch(异常类 对象名称){
		异常发生时的处理语句;
		}
		...
]
[finally{
		一定会运行到的程序代码;
		}
]	
		

异常的处理流程如下:

  1. 首先,我们把所有可能发生异常的语句都放到一个try之后由{}所形成的区块,这个区块称为“try区块”。程序通过try{}区块准备捕捉异常。try程序块若有异常发生,程序的运行便重点,并抛出“异常类所产生的对象”。
  2. 抛出的对象如果属于catch()括号内欲捕获的异常类,catch则会捕捉此异常,然后进入catch的块里继续运行。
  3. 无论try程序块是否捕捉到异常,或者捕捉到的异常是否与catch()括号内的异常相同,最终一定会运行finally块里的程序代码。

【注意】
finally块时可以省略的,如果省略了finally块,那么在catch()块运行结束后,程序将跳到try-catch块之后继续执行。

流程图如下:
在这里插入图片描述下面看一个例子:
不进行异常处理:

public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        System.out.println(arr[10]);
       
    }

在这里插入图片描述
使用异常处理就能正常编译:

 public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        try{
            System.out.println(arr[10]);
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("我在这里捕捉到一个异常");
        }
        System.out.println("hello!!!");

    }

在这里插入图片描述
如果我想要知道详细的异常信息的话,则需要使用异常对象的printStackTrace()方法:

在这里插入图片描述
【异常处理机制小结】
当异常发生时,通常用两种方法处理:

  1. 一种时交由Java默认的异常处理机制做处理。但这种处理方式,Java通常只能输出异常信息,接着便终止程序的运行
  2. 一种时用自行编写的try-catch-finally块来捕捉异常,这样的好处是可以灵活操控程序的流程,做出最适当的处理。

2.异常类的处理流程

。习惯上将Error类与Exception类统称为异常类,但二者本质上是不同点。
Error类通常指的是Java虚拟机出错,用户无法在程序里处理这种错误。
Exception类包含了一般性的异常,这些异常在捕捉到之后便可做妥善的处理,以确保程序继续运行。

下面是异常处理的流程:

  1. 如果程序发生异常,那么会自动地由JVM根据异常的类型,实例化一个指定异常类的对象,如果这个时候程序之中没有任何的异常操作,则这个异常类的实例化对象将交给JVM进行处理——进行异常信息的输出,而后中断程序执行
  2. 如果程序之中存在异常处理,则会由try语句捕获产生的异常类对象;然后将该对象与try之后的catch进行匹配,如果匹配成功,则使用指定的catch进行处理,如果没有匹配成功,则向后面的catch继续匹配,如果没有任何的catch匹配成功,则这个时候将交给JVM执行默认处理。
  3. 不管是否有异常都会执行finally程序,如果此时没有异常,执行完finally,则会继续执行程序之中的其他代码,如果此时有异常没有能够处理(没有一个catch可以满足),那么也会执行finally,但执行完finally之后,将默认交给JVM进行异常信息的输出,并且程序中断。

3.throws关键字

我们可以使用 throws 关键字, 把可能抛出的异常显式的标注在方法定义的位置. 从而提醒调用者要注意捕获这些异常。
格式如下:

访问权限 返回值类型 方法名称(参数列表)throws 异常类{
	//方法体;
}

上面格式包括两个部分:一个普通方法的定义,与方法定义模式无区别。方法后面紧跟”throws异常类“,它位于方法体{ }之前,用来检测当前方法是否有异常,若有,则将该异常提交给直接使用这个方法的方法。

 //定义私有化静态方法,并使用throws抛出异常
    //一旦方法出现异常,setZero()方法自己并不处理,而是将异常提交给它的上级调用这main()方法
    private static void setZero(int[] arr,int index)throws ArrayIndexOutOfBoundsException{
        arr[index]=0;
    }
    public static void main(String[] args) {
        int []arr=new int[5];
        try{
            setZero(arr,10);
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("数组超出绑定方位!");
            System.out.println("异常:"+e);
        }
        System.out.println("main()方法结束!");
    }

在这里插入图片描述

4.throw关键字

上面的所有异常类对象全部都是由JVM自动实例化的,但优势我们也想能进行异常类对象的实例化操作,手工抛出异常,则此时需要throw关键字。

public static void main(String[] args) {
        try {
            //抛出异常的实例化对象
            throw  new ArrayIndexOutOfBoundsException("n我是手工异常:n数组下标越界");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
        }
    }

在这里插入图片描述

三、自定义异常类

为了处理各种异常,Java可通过继承的方式运行用户编写自己的异常类,因为所有可处理的异常均继承自Exception类,因此自定义异常类也不例外。

语法如下:

class 异常名称 extends Exception{
...
}

我们可以在自定义异常类里编写方法处理相关时间,甚至不编写任何语句也可以正常工作,因为父类Exception已提供相当丰富的方法,通过几次子类均可以使用它们。

static class MyException extends Exception{
        public MyException(String msg){
            super(msg);//调用Exception类的构造方法,存入异常信息
        }
    }
    public static void main(String[] args) {
        try{
            throw new MyException("自定义异常");

        } catch (MyException e) {
            e.printStackTrace();
            System.out.println(e);
        }
    }

在这里插入图片描述


最后

前路漫漫啊,前路漫漫啊…

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>