java异常处理机制

1.JAVA异常
首先在写这篇博文的时候我们应该明白什么是异常?
(1)非正常的;不同于平常的,例如:异常现象;(2)非常:例如:任职期间异常紧张。【百度百科】
当我们在处理程序的过程中难免会不犯错误,为了更高效率的提高程序的可行性,詹姆斯大叔(詹姆斯·高斯林)为我们提供了一种异常处理的机制,以处理程序中可能出现的错误与异常。在这里我先大胆的将异常机制定义为:异常是用来以备不时之需
提供一张关于JAVA异常机制的类图

                      图1-1 Java异常类层次结构图

    在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出)。Throwable 指定代码中可用异常传播机制通过 Java 应用程序传输的任何问题的共性。
   Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,两个子类能够衍生出JAVA具体的异常类型。
   Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。在 Java中,错误通过Error的子类描述。

Exception(异常):是程序本身可以处理的异常。
Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。
注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。因此在实际的生产过程中Error是不进行特殊处理。

通常,Java的异常(包括Exception和Error)分为:
可查异常(编译器要求必须处置的异常):可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过(因为JAVA编译器是要检查的)。
不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。
结论:Error异常及其子类全部都是不可查异常,而Exception异常中RuntimeException异常及其子类全部为不可查异常,剩下的都是可查异常。它们区别主要就是当程序中出现不可查异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

2.JAVA异常处理机制
在 Java 应用程序中,异常处理机制为:抛出异常,捕捉异常。
抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。
捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
*注意:由于运行时异常的不可查性,为了更合理、更容易地实现应用程序,Java规定:不可查异常(运行异常)将由Java运行时系统自动抛出,允许应用程序忽略运行时异常。(包括全部Error及其子类、全部的RuntimeException及其子类);可查异常(非运行异常)必须由方法进行捕捉或者声明抛出方法之外,否则会报错。
能够捕捉异常的方法,需要提供相符类型的异常处理器。所捕捉的异常,可能是由于自身语句所引发并抛出的异常,也可能是由某个调用的方法或者Java运行时 系统等抛出的异常。也就是说,一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉的。
任何Java代码都可以抛出异常,如:自己编写的代码、来自Java开发环境包中代码,或者Java运行时系统。无论是谁,都可以通过Java的throw语句抛出异常。
从方法中抛出的任何异常都必须使用throws子句。
捕捉异常通过try-catch语句或者try-catch-finally语句实现。

3.JAVA异常捕获处理
1.try-catch语句
在Java中,异常通过try-catch语句捕获。其一般语法形式为:
try{
//TODO
}catch(Exception e1){
//TODO
}catch(Exception e2){
//TODO
}
关键词try后的一对大括号将一块可能发生异常的代码包起来,称为监控区域。Java方法在运行过程中出现异常,则创建异常对象。将异常抛出监控区域之 外,由Java运行时系统试图寻找匹配的catch子句以捕获异常。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。
匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。
例1 手动抛出并捕获异常
package demo;
/**
* @author wanghj
* @date 2016/02/29
*/
public class CSDN_Exception {
public static void main(String args[]){
int Divisor=1;
int Dividend=0;
try{
System.out.println(“Divisor:”+Divisor+” Dividend:”+Dividend);
if(0 == Dividend){
throw new Exception(“Dividend is zero!”);
}
}catch(Exception e){
System.out.println(“The Exception is:”+e.getMessage());
}
System.out.println(“The program is End!”);
}

}运行结果:Divisor:1 Dividend:0
The Exception is:Dividend is zero!
The program is End!

例2 自动抛出并手动捕获异常
package demo;
/**
* @author wanghj
* @date 2016/02/29
*/
public class CSDN_Exception {
public static void main(String args[]){
int Divisor=1;
int Dividend=0;
try{
System.out.println(“Divisor:”+Divisor+” Dividend:”+Dividend);
System.out.println(“Result:”+Divisor/Dividend);
}catch(Exception e){
System.out.println(“The Exception is:”+e.getMessage());
}
System.out.println(“The program is End!”);
}
}
}运行结果:Divisor:1 Dividend:0
The Exception is:/ by zero
The program is End!

例3 自动抛出并自动捕获异常
package demo;
/**
* @author wanghj
* @date 2016/02/29
*/
public class CSDN_Exception {
public static void main(String args[]){
int Divisor=1;
int Dividend=0;
System.out.println(“Result:”+Divisor/Dividend);
System.out.println(“The program is End!”);
}
}
}运行结果:Exception in thread “main” java.lang.ArithmeticException: / by zero
at demo.CSDN_Exception.main(CSDN_Exception.java:28)

例4 多异常匹配
package demo;
/**
* @author wanghj
* @date 2016/02/29
*/
public class CSDN_Exception {
public static void main(String args[]){
int Divisor=1;
int Dividend=0;
int[] arr=new int[5];
try{
System.out.println(“Divisor:”+Divisor+” Dividend:”+Dividend);
System.out.println(“arr[6]:”+arr[6]);
if(0 == Dividend){
throw new Exception(“Dividend is zero!”);
}
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println(“intArray数组下标越界异常。”);
}catch(ArithmeticException e) {
System.out.println(“除数为0异常。”);
}catch(Exception e){
System.out.println(“The Exception is:”+e.getMessage());
}
System.out.println(“The program is End!”);
}
}
}运行结果:Divisor:1 Dividend:0
intArray数组下标越界异常。
The program is End!

通过以上例子证明:1、一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束(try-catch以外的代码还将继续)。其他的catch子句不再有匹配和捕获异常类型的机会。
2、JAVA的catch机制是存在顺序的,从上而下依次进行匹配,一旦发生异常将不在进行匹配,因此尽量将高层次的异常放到后边。
3、JAVA的RuntimeException是可以自动抛出的。
2. try-catch-finally语句
在Java中,异常通过try-catch-finally语句捕获。其一般语法形式为:
try{
//TODO
}catch(Exception e1){
= //TODO
}catch(Exception e2){
//TODO
}finally{
//TODO
}
例5 带finally的异常处理机制
package demo;
/**
* @author wanghj
* @date 2016/02/29
*/
public class CSDN_Exception {
public static void main(String args[]){
int Divisor=1;
int Dividend=0;
try{
System.out.println(“Divisor:”+Divisor+” Dividend:”+Dividend);
if(0 == Dividend){
throw new Exception(“Dividend is zero!”);
}
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println(“intArray数组下标越界异常。”);
}catch(ArithmeticException e) {
System.out.println(“除数为0异常。”);
}catch(Exception e){
System.out.println(“The Exception is:”+e.getMessage());
}finally{
System.out.println(“The finally is Do!”);
}
System.out.println(“The program is End!”);
}
}

运行结果:Divisor:1 Dividend:0
The Exception is:Dividend is zero!
The finally is Do!
The program is End!

以上可得出结论:
try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。

在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了未处理异常。
2)在前面的代码中用了System.exit()退出程序(JVM多早终止)。
3)程序所在的线程死亡。
4)关闭CPU。

4.try、catch、finally语句块的执行顺序
1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;
2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;
图示try、catch、finally语句块的执行:

            图1-2  图示try、catch、finally语句块的执行

关于throw和throws的区别:
throw主要是用于方法之内的抛出异常,而throws则是用于方法之间的异常抛出;
throw只能抛出一个异常(Throwable类型),而throws能够抛出多个异常;
例如:
throw new Exception(“This is program!”);
public void function(param1,param2) throws Exception,MyException{
//TODO
}
为什么要使用throws抛出异常那?
——简单的理解就是高级程序员和中级程序员都会编程这个技能,但是当中级程序员遇到一个问题超出他的编程能力的时候,他需要将他遇到的问题交给高级程序员来处理,这就是所谓的抛出。

package demo;
/**
* @author wanghj
* @date 2016/02/29
*/
public class CSDN_Exception {
public static void CSDN_Do() throws Exception{
try{
int Divisor=1;
int Dividend=0;
int result=Divisor/Dividend;
System.out.println(“result is:”+result);
}catch(Exception e){
throw e;
}
}
public static void main(String args[]){
try{
CSDN_Do();
}catch(Exception e){
System.out.println(“Catch the throws Exception is:”+e.getMessage());
}
}
}

*当一个方法调用一个能抛出异常的方法时,该方法必须能够捕获到它的异常,这就是异常的向上传递机制(异常链)。这种机制可以解释为:
Java方法抛出的可查异常将依据调用栈、沿着方法调用的层次结构一直传递到具备处理能力的调用方法,最高层次到main方法为止。如果异常传递到main方法,而main不具备处理能力,也没有通过throws声明抛出该异常,将可能出现编译错误。

5.Java常见异常
Java中常见的异常类:
1. 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 非法参数异常
2.IOException
IOException:操作输入流和输出流时可能出现的异常。
EOFException 文件已结束异常
FileNotFoundException 文件未找到异常
3. 其他
ClassCastException 类型转换异常类
ArrayStoreException 数组中包含不兼容的值抛出的异常
SQLException 操作数据库异常类
NoSuchFieldException 字段未找到异常
NoSuchMethodException 方法未找到抛出的异常
NumberFormatException 字符串转换为数字抛出的异常
StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
IllegalAccessException 不允许访问某类异常
InstantiationException 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常

6.自定义异常
用户自定义异常类,只需继承Exception类即可。
7.Exception源码
package java.lang;

// Referenced classes of package java.lang:
// Throwable, String

public class Exception extends Throwable
{

public Exception()
{
}

public Exception(String s)
{
    super(s);
}

public Exception(String s, Throwable throwable)
{
    super(s, throwable);
}

public Exception(Throwable throwable)
{
    super(throwable);
}

protected Exception(String s, Throwable throwable, boolean flag, boolean flag1)
{
    super(s, throwable, flag, flag1);
}

static final long serialVersionUID = -3387516993124229948L;

}
8.作者忠告
1. 该代码的前提是程序能运行的过程,这是一个现在时或者是现在进行时,大家要注意一个地方是当程序出现Erro异常时,此时程序已经good game(GG)了,那么将不出现任何的异常处理机制,直接down 机;
2. 异常处理这种机制是对于一些未发生的事情的一种猜想以及对于一些可能发生的错误的一种处理,合理的对于异常机制使用能使得我们的程序兼容性得到有效的提高;
3. 虽然异常机制能够处理异常,但是这不意味着我们就放松对于我们程序的检查,一个完美的程序不是靠异常处理机制来完成的,需要我们仔细的去寻找程序的纰漏,尽可能的去避免错误的发生。

你可能感兴趣的:(java,异常处理,异常)