Java基础——异常解析

Posted David-Kuper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础——异常解析相关的知识,希望对你有一定的参考价值。

一、为什么要有异常


(1)为了协助排查程序出现的问题,上报错误日志。
(2)为了使出现错误的时候恢复正常。
(3)为了能够给用户一个提示。


二、异常的层次结构


三、异常类别


1、按照是否是编译期间检查分类

(1)可检查异常(编译期异常):

编译器要求强制检查的异常,一般来说都会有提示编译不通过。要么处理它,要么try..catch它。Exception中除了RuntimeExeption及其子类外都是可查异常,我们在程序中需要try…catch它们。

(2)不可检查异常(运行时异常):

编译器不要求强制检查的异常。包括运行时异常(RuntimeExeption)和错误(Error)。这类异常是不能够被编译器所检查到的,也无法try…catch.

2、按照异常类别分

(1)Error

是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。

这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。

(2)Exception:

是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。

  • 运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
    运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

  • 非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常。

注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。


四、异常的产生、捕获和处理


1、抛出异常:

//方法名抛出 
public void func2() throws Exception
     throw new Exception();
 

//方法体抛出
 public void func()
   try 


    catch (Exception e) 
     // TODO: handle exception
     throw e;
   

注意:

  1. throws出现在方法函数头;而throw出现在函数体。
  2. throws表示出现异常的一种可能性,并不一定会发生这些异常;
  3. throw则是抛出了异常,执行throw则一定抛出了某种异常对象

2、捕获异常

try
     // 可能发生异常的代码
    // 如果发生了异常,那么异常之后的代码都不会被执行

catch (Exception e)
    // 异常处理代码

finally
    // 不管有没有发生异常,finally语句块都会被执行

注意:

  1. 如果try块中存在System.exit(0);语句,那么就不会执行finally块中的代码,因为System.exit(0)会终止当前运行的Java虚拟机,程序会在虚拟机终止前结束执行。
  2. try块中有return语句时,仍然会首先执行finally块中的语句,然后方法再返回。
  3. 优先catch 指定类型的exception,将Exception e的捕获放在最后。

3、异常执行顺序:

(1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;

(2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;

(3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;在catch里面抛出异常是不会被捕获的。

图示try、catch、finally语句块的执行:

注意:

  1. 当程序没有异常的时候,try里面有返回值,如果有finnally语句块,那么虚拟机会将try里面return的值保存起来,继续执行finnally语句,执行完了之后再从寄存器将之前寄存的返回值取出return,这时候在finnally中修改返回值并不影响原先的返回,实际还是返回了原先的值。
  2. 当程序有异常的时候,按照catch先后进行匹配(就近匹配一个),匹配之后执行catch块代码,然后执行finnally代码。
  3. 如果在执行finnally代码时出现异常、调用exit()、线程死亡的情况下finnally不会被执行。
  4. finnally里面返回值不会影响到try代码里面的返回值,正常来说finnally里面是不应该有return的。
  5. 在catch语句块里面抛出的异常不会被捕捉,因为已经进入了catch说明错误应该已经处理了。

五、自定义异常


使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
在程序中使用自定义异常类,大体可分为以下几个步骤。

(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。

以上是关于Java基础——异常解析的主要内容,如果未能解决你的问题,请参考以下文章

[ Java学习基础 ] Java异常处理

异常处理

Java:异常处理

异常 异常处理

Java中的异常

Java中的异常