当前位置:   article > 正文

java异常机制详解篇一(基础知识点)_请解释java中的异常处理机制,并提供一些常见的异常类。

请解释java中的异常处理机制,并提供一些常见的异常类。

为什么需要异常?

异常处理己经成为衡量一门语言是否成熟的标准之一,目前的主流编程语言如 C++、 C#、Ruby、Python等大都提供了异常处理机制。增加了异常处理机制后的程序有更好的容错性,更加健壮 。java异常是java语言提供的一种识别和响应错误的一致性机制。java的异常机制可以使程序中异常处理代码和正常代码进行分离,保证了代码的优雅,在有效使用异常机制的情况下,程序可以回答出三个问题“什么”被抛出,“在哪”抛出,“为什么”会被抛出

java异常的架构

在这里插入图片描述
首先来看一下java异常的架构,java程序的所有非正常的情况分两种:异常(Exception)错误(Error),这两个都继承Throwable父类。

Throwable父类

Throwable类是java语言中所有异常和错误的超类,Throwable包含的两个子类,它们通常用于指示发生了异常情况,Throwable类包含了其创建线程时执行的堆栈的快照,它提供了printStackTrace()等接口用于捕获堆栈跟踪数据流等信息。

Error类

Error类及其实现了Error类的子类,在程序中表示的是出现了错误而且是无法处理的错误,Error类错误一般表示代码运行时java虚拟机出现了问题,通常有 Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)、OutOfMemoryError(内存不足错误)、StackOverflowError(栈溢出错误)等。此类错误发生时,java虚拟机将会终止线程。需要注意的是Error类的错误是不受检的错误,非代码性的错误,当这类错误发生时,不需要使用代码去接收并处理这类错误,而且还不应该去实现任何新的Error子类。

Exception类

异常指的是代码运行时产生了不合乎逻辑的事,比如说计算除法,但是有除数为零,这些异常是代码本身可以捕获并处理的,Exception(异常)又分为两类:运行时异常和编译时异常。

运行时异常

RuntimeException类及其子类指的是运行时异常,表示的是java虚拟机运行期间可能会出现的异常。 运行时异常有一个很重要的特点:java编译器不会检测它,可以理解为当程序出现这种异常的时候,如果程序没有通过throws声明抛出它,也没有使用try - catch语句捕获它,编译器也不会出现任何的问题,比如java程序中常见的空指针异常(NullPointerException),数组下标越界异常(ArrayIndexOutBoundException),类型转换异常(ClassCastException),算术异常(ArithmeticException)等等。

运行时异常属于不受检的异常,一般是由程序的逻辑错误引起的, 在程序中可以选择捕获并处理这种异常,当然,也可以不出来,因为java编译器不会检测运行时异常,程序中可以通过throws进行声明异常和抛出异常,也可以通过try - catch 语句进行捕获处理,如果产生运行时异常,则需要通过代码修饰进行避免。比如常见的除数不可以为零等常见的逻辑性异常。RuntimeException 异常会由 Java 虚拟机自动抛出并自动捕获(就算我们没写异常捕获语句运行时也会抛出错误!),此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。

编译时异常

在Exception的子类中,除了RuntimeException及其子类之外的异常,其余的异常都属于编译时异常,java编译器会在编译代码的过程中检测编译时异常,如果程序中出现了这种异常,比如说没有找到指定类异常(ClassNotFoundException)IO流异常(IoException),这些异常如果没有通过throws进行声明抛出,那么就必须使用try - catch语句进行捕获并处理,否则java编译器不允许这类代码通过编译,在程序开发的过程中,通常不会自定义该类异常,而是直接使用系统提供的异常类,编译时异常必须通过手动在代码中添加捕获语句进行处理。

实例代码:

public class DivTest {
    public static void main(String[] args) {
        try {
            // 正常输出
            int a = Integer.parseInt(String.valueOf(100));
            int b = Integer.parseInt(String.valueOf(10));
            // 数组越界异常
            //int a = Integer.parseInt(args[0]);
            //int b = Integer.parseInt(args[1]);
            // 输出数据格式异常
            //char a = 'a';
            //char b = 'b';
            // 算术异常
            //int a = 100;
            //int b = 0;
            int c = a / b;
            System.out.println("您输入的两个数相除的结果是:" + c );
        }
        catch (IndexOutOfBoundsException ie) {
            System.out.println("数组越界:运行程序时输入的参数个数不够");
        }
        catch (NumberFormatException ne) {
            System.out.println("数字格式异常:程序只能接受整数参数");
        }
        catch (ArithmeticException ae) {
            System.out.println("算术异常");
        }
        catch (Exception e) {
            System.out.println("未知异常");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

受检异常和不受检异常

在java异常机制体系中,所有的异常都可以划分为两种:受检异常(可查异常)不受检异常(不可查异常)

受检异常

受检异常指的是java编译器必须要处理的异常,程序在运行的过程中,经常容易出现不受控,不符合预期的情况,一旦发生此类情况,那就必须要采用某种方式进行处理,除了RuntimeException及其子类,其他的Exception异常都属于受检异常,编译器会检查此类异常,如果java程序被编译器检查出存在此类异常,那么它就会提示你需要处理这种异常,如果不进行处理,那么程序将无法通过编译。

不受检异常

不受检异常指的是java编译器不要求必须要处理的异常,如果程序中出现了此类的异常,即使程序中不使用try - catch语句进行捕获处理,同时也没有使用throws语句进行抛出,java编译器也可正常编译。不受检异常包括RuntimeException异常及其子类和Error类。

java异常关键字

有关java异常关键字的共有5个,分别是trycatchfinallythrowthrows

try关键字: 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
catch 关键字: 用于捕获异常。catch用来捕获try语句块中发生的异常。
finally 关键字: finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
throw 关键字: 用于抛出异常。
throws关键字: 用在方法签名中,用于声明该方法可能抛出的异常。

异常处理基础

在这里插入图片描述
java通过面向对象的方法进行异常处理,一旦方法抛出异常,系统将自动根据该异常对象寻找合适的异常处理器(Exception Handler)来处理该异常,把不同的各种异常进行分类,并提供了良好的接口。

在 Java 中,每个异常都是一个对象,它是 Throwable 类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws 和 finally。在Java应用中,异常的处理机制分为声明异常,抛出异常和捕获异常。

声明异常

在Java中,当前执行的语句必属于某个方法,Java解释器调用main方法执行开始执行程序。若方法中存在检查异常,如果不对其捕获,那必须在方法头中显式声明该异常,以便于告知方法调用者此方法有异常,需要进行处理。在方法中声明一个异常,方法头中使用关键字throws,后面接上要声明的异常。若声明多个异常,则使用逗号分割。如下所示:

public static void method() throws IOException, FileNotFoundException{
    //something statements
}
  • 1
  • 2
  • 3

注意: 非检查异常(Error、RuntimeException 或它们的子类)不可使用 throws 关键字来声明要抛出的异常。一个方法出现编译时异常,就需要 try-catch/ throws 处理,否则会导致编译错误,抛出异常。若是父类的方法没有声明异常,则子类继承方法后,也不能声明异常。

private static void readFile(String filePath) throws IOException {
    File file = new File(filePath);
    String result;
    BufferedReader reader = new BufferedReader(new FileReader(file));
    while((result = reader.readLine())!=null) {
        System.out.println(result);
    }
    reader.close();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

throws异常抛出规则

1、如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。

2、必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误。

3、仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。

4、调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

异常抛出

如果代码可能会引发某种错误,可以创建一个合适的异常类实例并抛出它,这就是抛出异常

直接抛出

public static double method(int value) {
    if(value == 0) {
        throw new ArithmeticException("参数不能为0"); //抛出一个运行时异常
    }
    return 5.0 / value;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

大部分情况下都不需要手动抛出异常,因为Java的大部分方法要么已经处理异常,要么已声明异常。所以一般都是捕获异常或者再往上抛。

封装异常再抛出

有时我们会从 catch 中抛出一个异常,目的是为了改变异常的类型。多用于在多系统集成时,当某个子系统故障,异常类型可能有多种,可以用统一的异常类型向外暴露,不需暴露太多内部异常细节。

private static void readFile(String filePath) throws MyException {    
    try {
        // code
    } catch (IOException e) {
        MyException ex = new MyException("read file failed.");
        ex.initCause(e);
        throw ex;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

捕获异常

程序通常在运行之前不报错,但是运行后可能会出现某些未知的错误,但是还不想直接抛出到上一级,那么就需要通过try…catch…的形式进行异常捕获,之后根据不同的异常情况来进行相应的处理。

自定义异常

习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函数(Throwable 的 toString 方法会打印这些详细信息,调试时很有用)

public class MyException extends Exception {
    public MyException(){ }
    public MyException(String msg){
        super(msg);
    }
    // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

异常基础总结

  • try、catch和finally都不能单独使用,只能是try-catch、try-finally或者try-catch-finally。
  • try语句块监控代码,出现异常就停止执行下面的代码,然后将异常移交给catch语句块来处理。
  • finally语句块中的代码一定会被执行,常用于回收资源 。
  • throws:声明一个异常,告知方法调用者。
  • throw :抛出一个异常,至于该异常被捕获还是继续抛出都与它无关。

Java编程思想一书中,对异常的总结。

  • 在恰当的级别处理问题。(在知道该如何处理的情况下了捕获异常。)
  • 解决问题并且重新调用产生异常的方法。
  • 进行少许修补,然后绕过异常发生的地方继续执行。
  • 用别的数据进行计算,以代替方法预计会返回的值。
  • 把当前运行环境下能做的事尽量做完,然后把相同的异常重抛到更高层。
  • 把当前运行环境下能做的事尽量做完,然后把不同的异常抛到更高层。 终止程序。
  • 进行简化(如果你的异常模式使问题变得太复杂,那么用起来会非常痛苦)。
  • 让类库和程序更安全。

常用的异常

在Java中提供了一些异常用来描述经常发生的错误,对于这些异常,有的需要程序员进行捕获处理或声明抛出,有的是由Java虚拟机自动进行捕获处理。Java中常见的异常类:

RuntimeException

1、java.lang.ArrayIndexOutOfBoundsException 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

2、java.lang.ArithmeticException 算术条件异常。譬如:整数除零等。

3、java.lang.NullPointerException 空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等

4、 java.lang.ClassNotFoundException 找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

5、java.lang.NegativeArraySizeException 数组长度为负异常。

6、java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常。

7、java.lang.SecurityException 安全性异常。

8、java.lang.IllegalArgumentException 非法参数异常

IOException

IOException:操作输入流和输出流时可能出现的异常。
EOFException 文件已结束异常。
FileNotFoundException 文件未找到异常。

其他异常

1、ClassCastException 类型转换异常类 ArrayStoreException 数组中包含不兼容的值抛出的异常。
2、SQLException 操作数据库异常类。
3、NoSuchFieldException 字段未找到异常。
4、NoSuchMethodException 方法未找到抛出的异常。
5、NumberFormatException 字符串转换为数字抛出的异常。
6、StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常。
7、IllegalAccessException 不允许访问某类异常
8、InstantiationException 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常。

文章参考

  1. 微信公众号 老炮说java
  2. https://www.pdai.tech/md/java/basic/java-basic-x-exception.html
  3. https://blog.csdn.net/ThinkWon/article/details/104390689
  4. https://blog.csdn.net/MacWx/article/details/90204111
  5. https://blog.csdn.net/hguisu/article/details/6155636
  6. https://blog.csdn.net/ThinkWon/article/details/101681073
  7. https://www.cnblogs.com/skywang12345/p/3544287.html
  8. https://www.codercto.com/a/33350.html
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/761153
推荐阅读
相关标签
  

闽ICP备14008679号