Java 异常框架

一.异常简介

1.Java提供的一种识别及响应错误业务的机制

2.将异常处理代码和正常业务代码分离,提高代码的健壮性

3.定位异常,获取异常信息。Java采用面向对象的方式,将发生的这一错误状况封装为异常对象。在有效使用异常的情况下,异常能清晰的回答what, where, why这3个问题:异常类型回答了“什么”被抛出,异常堆栈跟踪回答了“在哪”抛出,异常信息回答了“为什么”会抛出

二.异常架构

异常的架构有两种认识方式

第一种:根据我们是否有能力处理。将Throwable分为Error和Exception

第二种:根据编译器是否检查,是否一定要我们进行处理。将Throwable分为受检异常和非受检异常

 现在讲解第一种

1.Throwable

Throwable 是 Java 语言中所有错误与异常的超类。

Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示发生了异常情况。

Throwable 包含了其线程创建时线程执行堆栈的快照,它提供了 printStackTrace() 等接口用于获取堆栈跟踪数据等信息。

2.Error

定义:程序中无法处理的错误,表示运行应用程序中出现了严重的错误。Error 类及其子类。不受检异常。

特点:此类错误一般表示代码运行时 JVM 出现问题。通常有 Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。比如 OutOfMemoryError:内存不足错误;StackOverflowError:栈溢出错误。此类错误发生时,JVM 将终止线程。

这些错误是不受检异常,非代码性错误。因此,当此类错误发生时,应用程序不应该去处理此类错误。按照Java惯例,我们是不应该实现任何新的Error子类的!

3.Exception

程序本身可以捕获并且可以处理的异常。Exception 这种异常又分为两类:运行时异常和编译时异常。

运行时异常

定义:RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。

特点:Java 编译器不会检查它。不受检异常。也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。比如NullPointerException空指针异常、ArrayIndexOutBoundException数组下标越界异常、ClassCastException类型转换异常、ArithmeticExecption算术异常。此类异常属于不受检异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。虽然 Java 编译器不会检查运行时异常,但是我们也可以通过 throws 进行声明抛出,也可以通过 try-catch 对它进行捕获处理。如果产生运行时异常,则需要通过修改代码来进行避免。例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!

RuntimeException 异常会由 Java 虚拟机自动抛出并自动捕获(就算我们没写异常捕获语句运行时也会抛出错误!!),此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。

编译时异常

定义: Exception 中除 RuntimeException 及其子类之外的异常。

特点: Java 编译器会检查它。受检异常。如果程序中出现此类异常,比如 ClassNotFoundException(没有找到指定的类异常),IOException(IO流异常),要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。该异常我们必须手动在代码里添加捕获语句来处理该异常。

 

现在讲解第二种

Java 的所有异常可以分为受检异常(checked exception)和非受检异常(unchecked exception)。

1.受检异常

编译器要求必须处理的异常。正确的程序在运行过程中,经常容易出现的、符合预期的异常情况。一旦发生此类异常,就必须采用某种方式进行处理。 RuntimeException 及其子类外,其他的 Exception 异常都属于受检异常。编译器会检查此类异常,也就是说当编译器检查到应用中的某处可能会此类异常时,将会提示你处理本异常——要么使用try-catch捕获,要么使用方法签名中用 throws 关键字抛出,否则编译不通过。

2.非受检异常

编译器不会进行检查并且不要求必须处理的异常,也就说当程序中出现此类异常时,即使我们没有try-catch捕获它,也没有使用throws抛出该异常,编译也会正常通过。该类异常包括运行时异常(RuntimeException极其子类)和错误(Error)。

 

 

三.异常处理

异常处理分为三种:

1.声明异常

通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以在方法签名处使用 throws 关键字声明可能会抛出的异常。

注意

  • 非检查异常(Error、RuntimeException 或它们的子类)不可使用 throws 关键字来声明要抛出的异常。
  • 一个方法出现编译时异常,就需要 try-catch/ throws 处理,否则会导致编译错误。

2.抛出异常

(1)抛出自定义的异常  

例如在以下的场景:

int age = 0

age = -100;

System.out.println(age);

很正常的整型变量赋值,但是在我们眼中看来就不正常,谁的年龄会是负的呢

所以我们需要自己手动引发异常,这就是throw的作用

 

(2)要为抛出的异常附加详细的信息。

如果自定义异常是为了提示,一定要用try..catch,不要直接用throw往外抛。这样只能被框架捕获。

String name = null;
if(name==null){
    throw new NullPointerException("name不能为null");
}
System.out.println(name.getClass());

(3)与try-catch共同使用,如果将throw放在方法内部的catch()语句中,表示,你这个方法有了处理可能存在异常的机制,那就是一旦发生异常,方法内部的catch()语句直接捕捉了异常,并将异常类型的对象传递给该方法的调用处进行处理,方法调用处的catch语句直接会终止程序运行,抛出方法内部throw传递过来的异常。这属于程序本身自己检测到了异常而终止了程序运行。

3.捕获异常

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

四.异常类型与异常处理的对应

 

参考的大佬文章:https://thinkwon.blog.csdn.net/article/details/94346911

 

posted @ 2020-11-17 12:52  aczy  阅读(493)  评论(0编辑  收藏  举报