Java中的异常体系—认识异常

目录

1.初识异常

1)异常的概念

2)相关异常

3)避免异常的方式-防御式编程

LBYL

EAFP

2.异常的基本语法

1)使用try...catch...处理异常

2)多个catch块

3)使用异常的共同父类Exception捕获异常

4)关于异常的错误输出

调用栈

5)关于finally代码块-无论是否异常,都会执行的代码块

6)关于异常的返回值

7)关于异常的调用链

8)JDK新增的自动关闭接口

3.throws和throw

throws:

throw

4.异常体系

1)Error和Exception

Error

Exception

2)非受查异常和受查异常

非受查异常

受查异常

5. 自定义异常类

eg:异常抛出用户名密码错误:自定义异常实现登录


1.初识异常

1)异常的概念

异常是运行时抛出的程序错误,编译时的错误不属于异常

2)相关异常

1.算数的运算异常(除零异常)

书写方法: 报错的包名.类名.方法名称(错误行数),第一个出现报错的位置就是程序最开始出现错误的地方。

2.空指针异常

 3.数组的越界异常

3)避免异常的方式-防御式编程

LBYL

look before you leap:操作之前做充分检查

EAFP

先操作,遇到问题再处理

2.异常的基本语法

try{
    //存放所有可能出现异常的代码
}[catch(捕获相应的异常)...[0...N]]{//中括号的意思是可选,即可有可无
    //出现相应异常后的处理方式
}[finally]{
    //不强制要求写
    //无论是否发生异常,都会执行finally代码块,一般进行资源的释放
    //关闭资源的处理
}

1)使用try...catch...处理异常

int[] arr={10,20,30};
try{
    System.out.println(arr[10]);
}catch(ArrayIndexOutOfBoundsException e){//捕获相应异常
    System.out.println("数组下标越界");
}
System.out.println(arr[1]);

将可能会报错的代码放在try代码块,并用catch进行捕获。当出现异常后,不影响代码之后的正常代码arr[1]的执行。

2)多个catch块

catch只能处理对应种类的异常,1)中捕获的是数组越界异常,如果arr=null,则就是空指针异常,就不能用数组越界异常来抛出了,应该用对应的空指针异常抛出。所以,我们就需要增加catch段捕获相应异常。

int[] arr={10,20,30};
try{
    arr=null;
    System.out.println(arr[10]);
}catch(ArrayIndexOutOfBoundsException e){//捕获相应异常
    System.out.println("数组下标越界");
}catch(NullPointerException e){
    System.out.println("空指针异常");
}
System.out.println("异常后的代码");

注意:当出现异常时,JVM只会创建一个异常对象,catch捕获时会选择最接近(不是距离最接近)这个异常对象类型的catch段捕获,如此处运行结果:空指针异常    异常后的代码。【只会创建一个异常对象意味着只能捕获一次,而非有几个catch捕获几次】

3)使用异常的共同父类Exception捕获异常

当程序出现多种异常,并且有的异常编程时也不清楚时用到Exception,但不太推荐【一般明确会知道产生哪种异常,就捕获相应的异常即可,这样方便排查问题】,Exception可以接收所有的异常对象,只要发生了异常,都可以向上转型变为Exception对象。

4)关于异常的错误输出

Java中,一切皆对象,异常也是对象。上面写的空指针,数组越界,Exception->都是异常类,当产生错误时,JVM会构造一个相应的(相对应的异常类)异常对象传递给程序。

int[] arr={10,20,30};
try{
    System.out.println(arr[10]);
    //此处的e就是异常对象,默认是由JVM产生传递给catch代码段⭐
}catch(ArrayIndexOutOfBoundsException e){//捕获相应异常
    System.out.println("数组越界");
    //通过对象e调用,printStackTrace()方法叫打印错误堆栈信息--错误开始的位置
    e.printStackTrace();//⭐⭐
}
System.out.println("异常后的代码");

调用栈

方法之间是存在相互调用关系的, 这种调用关系我们可以用 "调用栈" 来描述.:在 JVM 中有一块内存空间称为 "虚拟机栈" 专门存储方法之间的调用关系.,当代码中出现异常的时候,我们就可以使用 e.printStackTrace(); 的方式查看出现异常代码的调用栈.。

5)关于finally代码块-无论是否异常,都会执行的代码块

int[] arr={10,20,30};
try{
    System.out.println(arr[10]);
    System.out.println("异常后的代码快");
}catch(ArrayIndexOutOfBoundsException e){
    System.out.println("数组越界");
    e.printStackTrace();
}finally {
    //无论上述代码是否产生异常,都会执行⭐
    System.out.println("finally代码块的代码");
}

通过运行发现,无论异常是否产生,finally代码块中的内容一定会执行,那么我们就将资源关闭操作等重要操作放在finally代码块中

finally:最终执行代码,善后处理。能走到finally,说明try和catch中的逻辑已经处理完毕了,只剩finally的最后处理操作。以打开文件举例:

6)关于异常的返回值

public static int testException(){
    try{
        String str=null;
        System.out.println(str.equals("test"));
        return 1;
    }catch(NullPointerException e){
        return 2;
    }finally {
        System.out.println("finally的代码块");
        return 3;
    }
}

一旦finally带了返回值,相当于try和catch的返回值就失效了。因为无论是否有异常,finally一定会执行,因此会覆盖try和catch的返回值。所以在finally中不推荐写返回值,除非返回值和异常无关,默认返回值才可以放在finally中。

7)关于异常的调用链

如果一个方法中没有合适的异常的处理方式,那么异常就会沿着调用栈向上传递。

异常会随着调用链不断向上传递,直到有一处捕获异常并处理为止,若调用过程都没有处理异常,最终会将异常抛到JVM,程序就终止了。

8)JDK新增的自动关闭接口

一旦一个类实现了AutoCloseable,就表示了该类具备了自动关闭的能力--声明在try代码块中会自动调用close方法

 在实现AutoCloseable接口后,【try(此处创建自动关闭类的实例){}】try中自动会进行关闭操作

3.throws和throw

一组关键字,搭配自定义异常使用

throws:

用在方法声明上,明确表示该方法有可能会产生该异常,但是不处理此异常,抛回给调用者处理。

public class ThrowsTest {
    public static void main(String[] args) {
        try{
            test();
        }catch(NullPointerException e){
            System.out.println("捕获空指针异常");
            e.printStackTrace();
        }
    }
    //调用test()方法有可能会产生空指针异常,但是test方法不处理此异常,谁调用谁处理
    public static void test() throws NullPointerException,ArrayIndexOutOfBoundsException{
        String str=null;
        System.out.println(str.length());
    }
}

分析:调用test()方法有可能会产生空指针异常,数组越界异常,但是test方法不处理此些异常,谁调用谁处理,即何处调用了test()方法,便在那处考虑处理异常。

throw

用在方法内部,表示人为产生异常对象并抛出

  public static void main(String[] args) {
        fun();
        System.out.println("fun后的代码块");
    }
    public static void fun(){
        //人为产生了个空指针异常对象,抛出给调用者
        throw new NullPointerException("没事干,抛个异常~");
        //抛出异常后,方法就会结束
    }

用法:之后数据结构的学习,在写栈等数据结构时,若栈为空,调用取出栈元素方法就可以使用throw手工抛出异常,告诉调用者栈为空,无法操作。

4.异常体系

1)Error和Exception

Error

指的是java运行时程序的内部错误和资源耗尽错误,应用程序不抛出此类异常,这种错误我们程序员无法捕获处理,一旦发生Error错误,程序只能告知用户出现错误,程序直接终止退出。

eg:

StackOverflowError:栈溢出Error ;

OutOfMemoryError:堆溢出Error:一般发生在递归调用太深,没有出口。

Exception

是我们程序员所使用的异常类的父类 

Java的异常体系分为两大类:非受查异常(图中蓝色框及其子类)受查异常上图红色框及其子类)

2)非受查异常和受查异常

非受查异常

所有非受查异常不强制程序使用try catch块处理(出错了就出错运行报错不出错就正常执行)

包含:Error以及RuntimeException(运行时异常,eg:空指针、类型转换、数组越界)及其子类都是非受查异常。

受查异常

除了非受查异常之外都是受查异常,必须显示使用try...catch...代码块异常处理或者throws抛出

包含:除了Error和RuntimeException以及其子类之外的其他异常都是受查异常,必须显示处理。

5. 自定义异常类

程序开发中一定会有一些错误是和具体业务相关,这种错误JDK是不可能提供相应的异常类,此时我们就需要继承已有的异常类,产生自定义的异常类。

若需要用户强制进行异常处理,继承Exception父类-受查异常

若不需要用户显示处理异常,继承RuntimeException父类-非受查异常

eg:异常抛出用户名密码错误:自定义异常实现登录

public class Login {
    public static final String USER="美女";
    public static final String PASSWORD="123456";

    public static void main(String[] args) {
        try{
            login();
            System.out.println("登陆成功");
        }catch (UserNameException e){
            e.printStackTrace();
        }catch (PasswordException e){
            e.printStackTrace();
        }
    }
    public static void login() throws UserNameException{
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name=scanner.next();
        System.out.println("请输入密码");
        String password=scanner.next();
        if(!name.equals(USER)){
            //用户名错误,抛出用户名错误异常:是个受查异常,必须有try..catch包裹或者throws抛出
               throw new UserNameException("用户名错误");
        }
        if(!password.equals(PASSWORD)){
            //抛出密码错误异常
            throw new PasswordException("密码错误");
        }
    }
}
class UserNameException extends java.lang.Exception{
    //继承受查异常,要进行异常地抛出
    //login()后接throws UserNameException抛出此异常
    public UserNameException(String msg){
        super(msg);
    }
}
class PasswordException extends RuntimeException{
    //这里进行了非受查异常,不需要进行显示异常处理。login() 后无需抛PasswordException
    public PasswordException(String msg){
        super(msg);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值