Java异常知多少

异常的引入

异常(Exception):在程序的运行过程中,发生了不正常的现象,阻止了程序的运行,我们称之为发生异常

通过代码引入:我们来写一个除法的程序

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入两个数:");
        int a = sc.nextInt();
        int b = sc.nextInt();
        System.out.println(a / b);
    }
}

上面程序当我们输入正确的int数值是,是可以运成功的
在这里插入图片描述
但是如果我们输入的值不是int型,或者被除数为0时,看结果:
在这里插入图片描述
在这里插入图片描述
像这种情况,因为我们输入的错误导致程序运行时出错,我们叫做运行时异常。

这种情况我们可以通过if-else解决这个异常

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入两个数:");
        if (sc.hasNextInt()) {
    
    
            int a = sc.nextInt();
            if (sc.hasNextInt()) {
    
    
                int b = sc.nextInt();
                if (b == 0) {
    
    
                    System.out.println("除数不能为0!!!");
                } else {
    
    
                    System.out.println(a / b);
                }
            } else {
    
    
                System.out.println("请输入一个整数!!!");
            }
        } else {
    
    
            System.out.println("请输入一个整数!!!");
        }
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

但是我们发现使用if-else有很多缺点:

  • 代码臃肿,业务代码和处理异常的代码混在一起。
  • 可读性差
  • 程序员需要花费大量的经历来维护这个漏洞
  • 程序员很难堵住所有的漏洞。

java下三种类型异常:

  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

Exception类

所有的异常类都是从java.lang.Exception类继承的子类,Exception类是Throwable类的子类,除了Exception类外,Throwable还有一个子类Error,Error 用来指示运行时环境发生的错误(例如,JVM 内存溢出。一般地,程序不会从错误中恢复);异常类有两个主要的子类:IOException 类和 RuntimeException 类。
在这里插入图片描述

内置异常类

标准运行时异常类的子类是最常见的异常类。由于 java.lang 包是默认加载到所有的 Java 程序的,所以大部分从运行时异常类继承而来的异常都可以直接使用。

Java 的非检查性异常
在这里插入图片描述
Java 定义在 java.lang 包中的检查性异常类
在这里插入图片描述

异常方法

在这里插入图片描述

try-catch-finally

基于if-else处理异常缺点太多,所以java中专门出了一个异常处理机制:异常三连:try-catch-finally.

把可能出现异常的代码放入try代码块中,然后将异常封装为对象,被catch后面的()中的那个异常对象接收,接收以后:执行catch后面的{}里面的代码,然后try-catch后面的代码,该怎么执行就怎么执行。

捕获异常

写法:

try{
    
    
    //程序代码
}catch(Exception e){
    
    
    //异常处理代码
}

修改之前的代码:

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入两个数:");
        try{
    
    
            int a=sc.nextInt();
            int b=sc.nextInt();
            System.out.println(a/b);
        }catch (Exception e){
    
    
            System.out.println("输入的数据有误!!!");
        }
        //如果出现异常,下面的代码不会被执行!!!
        System.out.println("hahahahaha");
    }
}

在这里插入图片描述

try-catch注意点:

  • try中没有异常,catch中代码不执行。
  • try中有异常,catch进行捕获:
    如果catch中异常类型和你出的异常类型匹配的话:走catch中的代码–>进行捕获
    如果catch中异常类型和你出的异常类型不匹配的话:不走catch中的代码–>没有捕获成功,程序相当于遇到异常了,中断了,后续代码不执行
  • try中如果出现异常,然后用catch捕获成功的话,那么try中后续的代码是不会执行的。
  • 如果catch捕获异常成功,那么try-catch后面的代码该执行还是执行没有影响。

catch中如何处理异常

1.输出自定义异常信息
在这里插入图片描述
2.打印异常信息:调用toString方法,显示异常的类名(全限定路径)
在这里插入图片描述
3.显示异常描述信息对应的字符串,如果没有就显示null
在这里插入图片描述
4.显示异常的堆栈信息:将异常信息捕获以后,在控制台将异常的效果给我们展示出来,方便我们查看异常
在这里插入图片描述
5.抛出异常
在这里插入图片描述

多重catch

一个try代码块后跟随多个catch代码块的情况就叫做多重捕获

语法:

try{
    
    
    //程序代码
}catch(异常类型1 异常名1){
    
    
    //异常处理代码
}catch(异常类型2 异常名2){
    
    
    //异常处理代码
}catch(异常类型3 异常名3){
    
    
    //异常处理代码
}

在实际中,可以在try语句后面添加任意数的catch块,这就取决于写的程序代码,如果tr保护代码中发生异常,异常先抛给第一个块,如果与第一个异常类型匹配,它就在这里被捕获,如果不匹配,它会被传递给第二个catch块,依次类推。一旦执行其中一条catch语句之后,后面的catch语句就会被忽略了!

注意:如果定义多重catch,不能把Exception异常类型放在第一个位置,因为Exception是所有异常类的父类,所以遇到异常就都会捕获,多重异常时Exception要放在最后有一个catch块,先写子类异常,再写父类异常。

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入两个数:");
        try {
    
    
            int a = sc.nextInt();
            int b = sc.nextInt();
            System.out.println(a / b);
        } catch (InputMismatchException e) {
    
    
            System.out.println("输入的数据不对!!!");
        } catch (ArithmeticException e) {
    
    
            System.out.println("除数不能为0!!!");
        } catch (Exception e) {
    
    
            System.out.println("程序出错!!!");
        }
    }
}

在这里插入图片描述

finally

finally 关键字用来创建在 try 代码块后面执行的代码块,无论是否发生异常,finally 代码块中的代码总会被执行,如果try程序中有return,先执行finally最后执行return。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句,finally 代码块出现在 catch 代码块最后.

try{
    
    
    //程序代码
}catch(异常类型1 异常变量1){
    
    
    //异常处理代码
}catch(异常类型2 异常变量2){
    
    
    //异常处理代码
}finally{
    
    
    //程序代码
}
public class Test {
    
    
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入两个数:");
        try {
    
    
            int a = sc.nextInt();
            int b = sc.nextInt();
            System.out.println(a / b);
        } catch (InputMismatchException e) {
    
    
            System.out.println("输入的数据不对!!!");
        } catch (ArithmeticException e) {
    
    
            System.out.println("除数不能为0!!!");
        } catch (Exception e) {
    
    
            System.out.println("程序出错!!!");
        }finally{
    
    
            System.out.println("finally里的必须运行!!!");
        }
    }
}

在这里插入图片描述
什么代码会放在finally中呢?–> 闭数据库资源,关闭IO流资源,关闭socket资源。

throw和throws

如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。

也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。

public class Test{
    
    
    public void method(double amout) throws RuntimeException{
    
    
        //制造异常
        throw new RuntimeException();
    }
}

一个方法可以声明多个异常,多个异常用逗号隔开

public class Test{
    
    
    public void method(double amout) throws RuntimeException,RemoteException{
    
    
        //制造异常
        throw new RuntimeException();
        ...
    }
}

throw和throws的区别:

  • 位置不同:throw:方法内部;throws: 方法的签名处,方法的声明处
  • 内容不同:throw+异常对象(检查异常,运行时异常);throws+异常的类型(可以多个类型,用,拼接)
  • 作用不同:throw:异常出现的源头,制造异常;throws:在方法的声明处,告诉方法的调用者,这个方法中可能会出现我声明的这些异常。然后调用者对这个异常进行处理:
    要么自己处理要么再继续向外抛出异常
区别 throw throws
位置不同 方法内部 方法的签名处,方法的声明处
内容不同 throw+异常对象(检查异常,运行时异常) throws+异常的类型(可以多个类型,用,拼接)
作用不同 异常出现的源头,制造异常 在方法的声明处,告诉方法的调用者,这个方法中可能会出现我声明的这些异常。然后调用者对这个异常进行处理

自定义异常

在 Java 中你可以自定义异常,可以像下面这样定义自己的异常类:也可以重写异常类的方法。

public class MyException extends Exception{
    
    
    //重写
    public String getMessage(){
    
    
        //代码
    }
}

自定义的异常可以继承:运行时异常(RuntimeException)

public class MyException extends RuntimeException {
    
    
    public MyException(){
    
    
    }
    public MyException(String message){
    
    
        super(message);
    }
}

也可以继承检查异常(Exception)

public class MyException extends Exception {
    
    
    public MyException(){
    
    
    }
    public MyException(String message){
    
    
        super(message);
    }
}

如果继承的是运行时异常,那么在使用的时候无需额外处理
如果继承的是检查异常,那么使用的时候需要try-catch捕获或者throws向上抛

猜你喜欢

转载自blog.csdn.net/weixin_47383392/article/details/124295420