【JavaSE】认识异常

目录

一、初识异常

1.1 常见的异常

1.2 Java异常体系

1.3 防御式编程

二、异常的基本用法

2.1 捕获异常

case1:如果不处理异常会发生什么?

case2:使用try catch后的程序执行过程

case3:catch只能处理对应种类的异常

case4:catch可以有多个

case5:也可以用一个catch捕获所有异常(不推荐这样写)

case6:finally表示最后的善后工作,例如释放资源

case7:使用try负责回收资源(finally回收资源的等价写法)

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

2.2 异常处理流程

2.3 抛出异常

2.4 异常说明

2.5 finally的注意事项

三、自定义异常类

总结


一、初识异常

1.1 常见的异常

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

异常是“运行时”的事情,是代码已经跑起来了出现的异常。这时程序已经编译通过得到class文件了,再由JVM执行过程中出现的错误。

编译:如果代码写错了,比如出现一些语法错误,编译不通过,报的是编译错误,这时代码还没跑起来。

常见的异常:

①除以0

②数组下标越界

 ③访问null对象

1.2 Java异常体系

Java内置了丰富的异常体系,用来表示不同情况下的异常。下图表示Java内置的异常类之间的继承关系:

  顶层类Throwable派生出两个重要的子类,Error和Exception。

其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现,除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现.
Exception 是异常类的父类,其中 Exception 有一个子类称为 RuntimeException , 这里面又派生出很多我们常见的异常类NullPointerException , IndexOutOfBoundsException 等
Java语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为非受查异常, 所有的其他异常称为受查异常.

 如果一段代码可能抛出受查异常, 那么必须显式进行处理。显式处理的方式有两种:
a) 使用 try catch 包裹起来
b) 在方法上加上异常说明, 相当于将处理动作交给上级调用者

1.3 防御式编程

错误在代码中是客观存在的,因此需要让程序出现问题的时候及时通知程序员。有两种方式:

LBYL:在操作之前就做充分的检查。

EAFP:“事后获取原谅比事前获取许可更加容易”,先操作,遇到问题再处理。

二、异常的基本用法

2.1 捕获异常

 try代码块中放的是可能出现异常的代码。

catch代码中放的是出现异常后的处理行为。

finally代码块中的代码处理善后工作,会在最后执行。

catch和finally都可以根据情况选择加或者不加。

case1:如果不处理异常会发生什么?

case2:使用try catch后的程序执行过程

public static void main(String[] args) {
        int[] array = {1,2,4};
        try{
            System.out.println("aaa");
            System.out.println(args[100]);
            System.out.println("bbb");
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace(); // 打印出异常的调用栈
        }
        System.out.println("我不是try里面的内容哦");
    }

 一旦try中出现异常,那么try代码块中的代码就不会继续执行,而是交给catch中的代码来执行。catch执行完毕后会继续往下执行。

case3:catch只能处理对应种类的异常

public static void main(String[] args) {
        int[] array = {1,2,4};
        try{
            System.out.println("aaa");
            System.out.println(args[100]);
            System.out.println("bbb");
        }catch (ArithmeticException e){
            e.printStackTrace(); // 打印出异常的调用栈
        }
        System.out.println("我不是try里面的内容哦");
    }

 异常不匹配,catch并不能捕获到数组越界异常。

case4:catch可以有多个

一段代码可能会抛出多种不同的异常,不同的异常有不同的处理方式,因此可以搭配多个catch代码。

    // 写法1
    public static void main(String[] args) {
        int[] array = {1,2,4};
        try{
            System.out.println("aaa");
            System.out.println(args[100]);
            System.out.println("bbb");
        }catch (ArithmeticException e){
            e.printStackTrace(); // 打印出异常的调用栈
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
        }
        System.out.println("我不是try里面的内容哦");
    }
    // 写法2
    // 如果多个异常的处理方式完全相同,也可以这样写
    public static void main(String[] args) {
        int[] array = {1,2,4};
        try{
            System.out.println("aaa");
            System.out.println(args[100]);
            System.out.println("bbb");
        }catch (ArithmeticException | ArrayIndexOutOfBoundsException e){
            e.printStackTrace(); // 打印出异常的调用栈
        }
        System.out.println("我不是try里面的内容哦");
    }

case5:也可以用一个catch捕获所有异常(不推荐这样写)

Exception类是所有异常类的父类,因此可以用这个类型来捕获所有异常。

 public static void main(String[] args) {
        int[] array = {1,2,4};
        try{
            System.out.println("aaa");
            System.out.println(args[100]);
            System.out.println("bbb");
        }catch (Exception e){
            e.printStackTrace(); // 打印出异常的调用栈
        }
        System.out.println("我不是try里面的内容哦");
    }

case6:finally表示最后的善后工作,例如释放资源

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try{
            int a = scanner.nextInt();
            System.out.println(a);
        }catch (InputMismatchException e){
            e.printStackTrace();
        }finally {
            scanner.close();
        }
    }

无论是否存在异常,finally中的代码一定都会执行到。保证最终一定会执行到Scanner的close方法。

case7:使用try负责回收资源(finally回收资源的等价写法)

public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            int a = scanner.nextInt();
            System.out.println(a);
        } catch (InputMismatchException e) {
            e.printStackTrace();
        }
    }

try上有一个加深底色,这是IDEA针对我们的代码提出了一些更好的建议。鼠标在try上停留,按住ctrl+enter,会弹出一个改进方案的弹窗,选择后,代码自动调整为如下代码

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

public static void main(String[] args) {
       try{
           func();
       }catch (ArrayIndexOutOfBoundsException e){
           e.printStackTrace();
       }
        System.out.println("我在trycatch的后面");
    }
    public static void func(){
       int[] elem = {1,2,3};
        System.out.println(elem[100]);
    }

注意:如果向上一直传递都没有合适的方法处理异常,最终就会交给JVM处理,程序就会异常终止。

2.2 异常处理流程

程序先执行try中的代码。

如果try中的代码出现异常,就会结束try中的代码,看出现的异常和catch中的异常类型是否匹配。

如果找到匹配的异常类型,就会执行catch中的代码。

如果没有找到匹配的异常类型,就会将异常向上传递给上层调用者。

无论是否找到匹配的异常类型,finally中的代码都会被执行到。

如果上层调用者也没有处理异常,就继续向上传递。

一直到main方法也没有合适的代码处理异常,就会交给JVM来进行处理,此时程序就会异常终止。

2.3 抛出异常

程序员可以利用throw,手动的抛出某个异常。

public static void main(String[] args) {
        int x = 0;
        if (x == 0) {
            throw new RuntimeException("抛出异常");
        }
    }

 2.4 异常说明

在处理异常的时候,通常希望知道这段代码中可能出现哪些异常。可以使用throws关键字,把可能抛出的异常显示的标注在方法定义的位置,提醒调用者要注意捕获这些异常。

public static int divide(int x,int y) throws ArithmeticException{
        if(y == 0){
            throw new ArithmeticException("除数为0哦");
        }
        return x/y;
    }

2.5 finally的注意事项

finally中的代码保证一定会执行到,这也会带来一些麻烦。

public static void main(String[] args) {
    System.out.println(func());  // 20
}
public static int func(){
    try{
        return 10;
    }finally {
        return 20;
    }
}

①finally中没有return,try和catch中有return,先执行finally,再return;

②如果finally中也有return,就会执行finally中的return,从而不会执行到try中原有的return。

一般不建议在finally中写return。

三、自定义异常类

class UserError extends Exception{
    public UserError(String message){
        super(message);
    }
}
class PasswordError extends Exception{
    public PasswordError(String message){
        super(message);
    }
}
public class TestDemp6 {
    public static String username = "admin";
    public static String password = "1111";
    public static void login(String name,String password) throws UserError,PasswordError{
        if(!username.equals(name)){
            throw new UserError("用户名错误");
        }
        if(!username.equals(password)){
            throw new PasswordError("密码错误");
        }
    }
    public static void main(String[] args) {
       try{
           login("zhangsan","1111");
       }catch (UserError userError){
           userError.printStackTrace();
       }catch (PasswordError passwordError){
           passwordError.printStackTrace();
       }
    }
}

注意事项:

自定义异常通常会继承自Exception或者RuntimeException

继承自Exception的异常默认是受查异常

继承自RuntimeException的异常默认是非受查异常。

总结

异常的处理:使用try-catch包裹、加上声明(throws)交给上层调用者处理。

当出现异常后,try里面的内容不再继续执行,程序接着往下执行。

catch需要捕获对应的异常才能处理异常,也能有多个catch语句。

finally最后都会被执行到。不建议在finally里面写return。

catch和finally都是可有可无的。

受查异常必须被显示的处理。

不建议使用catch捕获Exception。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘减减

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值