一、异常的定义

 

1.1、异常的基础知识

什么是异常?在Java编程语言中,异常类定义程序中可能遇到的轻微的错误条件。可以写代码来处理异常并继续程序执行,而不是让程序中断。

在程序执行中,任何中断正常程序流程的异常条件就是错误或异常。例如,发生下列情况时,会出现异常:

1)想打开的文件不存在

2)网络连接中断

3)受控操作数超出预定范围

非常感兴趣的正在装载的类文件丢失在Java编程语言中,错误类定义被认为是不能恢复的严重错误条件。在大多数情况下,当遇到这样的错误时,建议让程序中断。

    Java 编程语言实现异常处理来帮助建立弹性代码。在程序中发生错误时,发现错误的方法能抛出一个异常到其调用程序,发出已经发生问题的信号。然后,调用方法捕获抛出的异常,在可能时,再恢复回来。这个方案给程序员一个写处理程序的选择,来处理异常。

通过浏览API,可以决定方法抛出的是什么样的异常。

 

1.2、异常实例                                                                            

考虑一下HelloWorld.java程序版本的简单扩展,它通过信息来循环:

public class HelloWorld{

public static void main (String args[]) {  

int i = 0;  

String greetings [] = {

"Hello world!",

"No, I mean it!",

"HELLO WORLD!!"    };

 

while (i < 4) {

System.out.println (greetings[i]);

i++;

}

}

}

正常情况下,当异常被抛出时,在其循环被执行四次之后,程序终止,并带有错误信息,

就象前面所示的程序那样。

 

Hello world!

No, I mean it!

HELLO WORLD!!

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3

at demo1.HelloWorld.main(HelloWorld.java:20) 

 

异常处理允许程序捕获异常,处理它们,然后继续程序执行。它是分层把关,因此,错误情况不会介入到程序的正常流程中。特殊情况发生时,在与正常执行的代码分离的代码块中被处理。这就产生了更易识别和管理的代码。

 

 

二、异常处理

Java 提供了一种异常处理模型,它使您能检查异常并进行相应的处理。它实现的是异常处理的抓抛模型。使用此模型,您只需要注意有必要加以处理的异常情况。Java 提供的这种异常处理模型,代替了用返回值或参数机制从方法返回异常码的手段。

异常处理的抓抛方法有两大优点:

1)异常情况能仅在有必要之处加以处理,而不在其发生处和需要进行处理处之间的每一级上均进行处理。

2)能够编写统一的、可重用的异常处理代码。

 

应该区别对待程序中的正常控制流和异常处理流。当然,异常处理流也是程序中的控制流。当异常发生时,抛出一个异常。异常伴随调用链,直到它们被捕获或程序退出为止。

下面是Java语言中的异常处理块的模型:

 try{

//放置可能出现异常的代码

}catch(Exception1 el){

  //如果try块抛出异常对象的类型为Exceptionl,那么就在这里进行处理

}catch(Exception2 e2){

  //如果try块抛出异常对象的类型为Exception2,那么就在这里进行处理

}catch(ExceptionN eN){

   //如果try块抛出异常对象的类型为ExceptionN,那么就在这里进行处理

}finally{

 //不管是否有异常发生,始终执行这个代码块

}

 

在未提供适当异常处理机制的程序中,无论何时发生异常,程序均会异常中断,而之前分配的所有资源则保持其状态不变。这会导致资源遗漏。要避免这一情况,在适当的异常处理机制中,我们可以将以前由系统分配的所有资源返还给系统。所以,当异常可能发生时,要牢记必须对每一异常分别进行处理。

例如我们处理文件I/O,在打开文件时发生IOException,程序异常中断而没有机会关闭该文件,这可能会毁坏文件而且分配给该文件的操作系统资源可能未返还给系统。

2.1、try块                                                                                

try块由一组可执行语句组成,在执行它们时可能会抛出异常。try块后可随一个或多个catch块,用来捕获在try中抛出的异常。另一方面,try不可以跟随在catch块之后。

也就是说:try语句块中包含可能会产生异常的语句 

int demo=0;

 try{

  System.out.println(20/demo);

}

 

 语句 System.out.println(20/demo);

会抛出一个异常,原因是试图用0去除一个数。程序会被成功编译,但当运行该程序时,程序将会发生异常而中断,异常可在catch块中被捕获,try块可以嵌套:

try{

 statement 1;

 statement 2;

try{

 statement 1;

 statement 2;

}catch(Exception e){

 //异常处理

}

}catch(Exceptione){

   //异常处理

}

  

 try块嵌套时,首先执行内部的try块,该块中引发的任何异常在随后的catch中被捕获;如果未发现与该内部块匹配的catch块,则检查外部try块的catch块;如果发现匹配的catch块,那么在该块中处理这一异常,否则Java运行时环境(JRE)处理这一异常。

 

2.2catch                                                                          

catch块,从其名称就可以看出,是用来捕获并处理try中抛出的异常的代码块。没有 try 块,catch 块不能单独存在,我们可有多个 catch 块,以捕获不同类型的异常。

下面是 catch块的语法:

try{

    }catch(异常类型  e){

    } 

这里,e是异常类型类的对象,利用这一对象,我们可以输出这一异常的详细信息下面是catch/try块的一个简单示例:

public class test {

 

 public static void main(String args[]) {  

     int demo=0;

     try{

        System.out.println(20/demo);

    }catch(ArithmeticException a){

        System.out.println("异常");

    }

  }

}

   

 上述程序的输出结果是:“异常”

注意:当多个catch块存在的时候,从上往下catch异常的范围应该从小到大,因为catch 块的运行机制是找到一个匹配的就进行处理了,如果把范围大的放在前面,那么后面的代码就没有机会运行了,这会是一个编译异常,示例如下:

比如下面这个是正确的:

public static void main(String[] args) {

  try{    

  int i = 5/0;

  }catch(ArithmeticException  e){  

 

  e.printStackTrace();

 

  }catch(Exception err){   

  

  err.printStackTrace();

  }   

 }

 

而下面这个就是错误的了,编译都发生了错误:

public  class test {

 public static void main(String[] args) {

  try{   

 int i = 5/0;

  }catch(Exception err){

  

        err.printStackTrace();

        

  }catch(ArithmeticException  e){  

  

  e.printStackTrace();

  }   

 }

}  

2.3、finally块          

finally块表示:无论是否出现异常,都会运行的块。通常在finally块中可以编写资源返还给系统的语句,这些语句包括但不限于:

1)释放动态分配的内存块:

2)关闭文件;

3)关闭数据库结果集;

4)关闭与数据库建立的连接;它紧跟着最后一个块,是可选的,不论是否抛出异常,finally块总会被执行。

finally块的语法如下:

try{

}catch(异常类型1  e){

}catch(异常类型2  e){

}finally{

下面的程序显示的是 finally 块的使用 

public class test {  

static String name;  

static int n01, n02;

public static void main(String args[]) {  

   try {

name = "Aptech Limited";

n01 = Integer.parseInt(args[0]);

n02 = Integer.parseInt(args[1]);

System.out.println("Division is" + n01 / n02);

} catch (Exception e) {

e.printStackTrace();

}finally {

System.out.println("finally");

}

     

}

}

您从下面的命令行执行此程序:

java.lang.ArrayIndexOutOfBoundsException: 0

at demo1.test.main(test.java:10)

 finally

说明:当您用不同的命令行参数执行此程序时,均会看见“finally executed”的输出这意味着,无论try块是否抛出异常,都会执行finally块。 

 

2.4、try、catch、finally之间关系

1)try 块不能单独存在,后面必须跟 catch 块或者 finally 块 

2)三者之间的组合为:try—catch 、try—catch—finally 、 try—finally 这几种是合法的 

3)一个 try 块可以有多个 catch 块,从上到下多个 catch 块的范围为从小到大 

 

2.5、throw语句

 throw语句用来从代码中主动抛出异常。throw的操作数是任一种异常类对象。下面是 throw关键字的一个示例:

 

public static void main(String[] args) {

try {  

int i = 5/0;

} catch (ArithmeticException i) {

 try {

throw new Exception("异常");

} catch (Exception e) {

e.printStackTrace();

}

}

} 

2.6、throws语句

throws 用来在方法定义时声明异常。 

Java 中对异常的处理有两种方法,一个就是 try-catch,然后自己处理;一个就是不做处理,向外 throws,由别人去处理。 

Java 语言要求在方法定义中列出该方法抛出的异常: 

public Class Example

{

    public static void exceptionExample() throws ExampleException,LookupException

{

}

}

在上面的示例中,exceptionExample()声明包括 throws 关键字,其后列出了此方法可能抛出的异常列表。在此案例中列出的是 ExampleException LookupException。 

比如前面那个例子写完整如下: 

public class test {  

public static void main(String args[])throws Exception {

  try {   

  int i = 5/0;

  } catch (ArithmeticException i) {

  throw new Exception("异常");

  }

  }

}  

2.7、调用栈机制            

如果方法中的一个语句抛出一个没有在相应的try/catch块中处理的异常,那么这个异常就被抛出到调用方法中。如果异常也没有在调用方法中被处理,它就被抛出到该方法的调用程序。这个过程要一直延续到异常被处理。如果异常到这时还没被处理,它便回到main(),而且,即使main()不处理它,那么,该异常就异常地中断程序。

考虑这样一种情况,在该情况中 main()方法调用另一个方法(比如,first()),然后它调用另一个(比如,second())。如果在second()中发生异常,那么必须做一个检查来看看该异常是否有一个 catch;如果没有,那么对调用栈(first())中的下一个方法进行检查,然后检查下一个(main())。如果这个异常在该调用栈上没有被最后一个方法处理,那么就会发生一个运行时错误,程序终止执行。

2.8、处理或声明规则                                                                            

为了写出健壮的代码,Java 编程语言要求,当一个方法在栈(即,它已经被调用)上发生Exception(它与Error或RuntimeException不同)时,那么,该方法必须决定如果出现问题该采取什么措施。

程序员可以做满足该要求的两件事:

第一, 通过将 try{}catch(){}块纳入其代码中,在这里捕获给被命名为属于某个父类的异常,并调用方法处理它。即使catch块是空的,这也算是处理情况。第二, 让被调用的方法表示它将不处理异常,而且该异常将被抛回到它所遇到的调用方法中。按如下所示通过用throws子句标记的该调用方法的声明来实现的: public void troublesome() throws IOException

    关键字throws之后是所有异常的列表,方法可以抛回到它的调用程序中。尽管这里只显示了一个异常,如果有成倍的可能的异常可以通过该方法被抛出,那么,可以使用逗号分开的列表。

是选择处理还是选择声明一个异常取决于是否给你自己或你的调用程序一个更合适的候选的办法来处理异常。

 

三、Exception 类的层次

所有的异常类是从 java.lang.Exception 类继承的子类。

Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。

Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。

Error 用来指示运行时环境发生的错误。

例如,JVM 内存溢出。一般地,程序不会从错误中恢复。

异常类有两个主要的子类:IOException 类和 RuntimeException 类。

JAVA异常(十)

 

   3.1Java内置异常类

Java 语言定义了一些异常类在 java.lang 标准包中。

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

 

Java 根据各个类库也定义了一些其他的异常,下面的表中列出了 Java 的非检查性异常。

 

 

异常                                       描述

1)ArithmeticException 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。

2)ArrayIndexOutOfBoundsException 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。

3)ArrayStoreException 试图将错误类型的对象存储到一个对象数组时抛出的异常。

4)ClassCastException 当试图将对象强制转换为不是实例的子类时,抛出该异常。

5)IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。

6)IllegalMonitorStateException 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。

7)IllegalStateException 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。

8)IllegalThreadStateException 线程没有处于请求操作所要求的适当状态时抛出的异常。

9)IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。

10)NegativeArraySizeException 如果应用程序试图创建大小为负的数组,则抛出该异常。

NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常

11)NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。

12)SecurityException 由安全管理器抛出的异常,指示存在安全侵犯。

13)StringIndexOutOfBoundsException 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。

14)UnsupportedOperationException 当不支持请求的操作时,抛出该异常。

 

下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。

 

异常                        描述

1)ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常。

2)CloneNotSupportedException 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。

3)IllegalAccessException 拒绝访问一个类的时候,抛出该异常。

4)InstantiationException 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。

5)InterruptedException 一个线程被另一个线程中断,抛出该异常。

6)NoSuchFieldException 请求的变量不存在

7)NoSuchMethodException请求的方法不存在

 

3.2、扩展知识

JAVA异常(十)

如图可以看出所有的异常跟错误都继承与Throwable类,也就是说所有的异常都是一个对象。

 

从大体来分异常为两块:

 

1、error---错误 : 是指程序无法处理的错误,表示应用程序运行时出现的重大错误。例如jvm运行时出现的OutOfMemoryError以及Socket编程时出现的端口占用等程序无法处理的错误。

 

2、Exception --- 异常 :异常可分为运行时异常跟编译异常

 

 1)运行时异常:即RuntimeException及其之类的异常。这类异常在代码编写的时候不会被编译器所检测出来,是可以不需要被捕获,但是程序员也可以根据需要进行捕获抛出。常见的RUNtimeException有:NullpointException(空指针异常),ClassCastException(类型转换异常),IndexOutOfBoundsException(数组越界异常)等。

 2)编译异常:RuntimeException以外的异常。这类异常在编译时编译器会提示需要捕获,如果不进行捕获则编译错误。常见编译异常有:IOException(流传输异常),SQLException(数据库操作异常)等。

3、java处理异常的机制:抛出异常以及捕获异常 ,一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉的。

 

4、throw跟throws的区别:

 

public void test() throws Exception {

    throw new Exception();

}

从上面这一段代码可以明显的看出两者的区别。throws表示一个方法声明可能抛出一个异常,throw表示此处抛出一个已定义的异常(可以是自定义需继承Exception,也可以是java自己给出的异常类)。

 

5、接下来看一下如何捕获异常:

 

1)首先java对于异常捕获使用的是try---catch或try --- catch --- finally 代码块,程序会捕获try代码块里面的代码,若捕获到异常则进行catch代码块处理。若有finally则在catch处理后执行finally里面的代码。然而存在这样两个问题:

 

a.看如下代码:

 

try{

    //待捕获代码

}catch(Exception e){

    System.out.println("catch is begin");

    return 1 ;

}finally{

     System.out.println("finally is begin");

}

在catch里面有一个return,那么finally会不会被执行呢?答案是肯定的,上面代码的执行结果为:

 

catch is begin

finally is begin  

也就是说会先执行catch里面的代码后执行finally里面的代码最后才return1 ;

 

b.看如下代码:

 

try{

   //待捕获代码    

}catch(Exception e){

    System.out.println("catch is begin");

    return 1 ;

}finally{

     System.out.println("finally is begin");

     return 2 ;

}

在b代码中输出结果跟a是一样的,然而返回的是return 2 ; 原因很明显,就是执行了finally后已经return了,所以catch里面的return不会被执行到。也就是说finally永远都会在catch的return前被执行。(这个是面试经常问到的问题哦!)

 

6、对于异常的捕获不应该觉得方便而将几个异常合成一个Exception进行捕获,比如有IO的异常跟SQL的异常,这样完全不同的两个异常应该分开处理!而且在catch里处理异常的时候不要简单的e.printStackTrace(),而是应该进行详细的处理。比如进行console打印详情或者进行日志记录。

 

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

相关文章:

  • 2021-10-05
  • 2021-09-23
  • 2021-05-20
  • 2022-12-23
  • 2021-06-23
  • 2021-09-14
  • 2021-04-27
  • 2021-10-23
猜你喜欢
  • 2021-06-18
  • 2021-10-23
  • 2021-06-14
  • 2021-10-14
  • 2021-06-03
  • 2022-02-09
  • 2021-08-06
相关资源
相似解决方案