不管使用的是哪种语言进行程序设计,都会产生各种各样的错误。Java提供了强大的异常处理机制。在Java中所有的异常被封装到一个类中,程序出错时将异常抛出。
一个程序能正常准确的运行,这是一个程序的基本要求。但一个健壮的程序则需要考虑很多会使程序失效的因素,即他要在非正常情况下也要进行必要的处理。程序运行时的错误,对Java而言是一种异常。处理异常就是保证异常时不会导致丢失数据或破坏系统运行等灾难性后果。
异常基本概念
异常(Exception)也称为例外,指的是所有可能造成计算机无法正常处理的情况,如果没有妥善安排,严重可以使得计算机死机。异常处理是一种特定的程序错误处理机制。为了让程序员更加关注正常的程序执行序列而设计的。异常处理提供了一种标准的方法以处理错误,可以发现预知以及不可预知的问题,及允许开发者识别查出和修改错漏之处。
处理错误方法有如下特点
1,不需要打乱程序结构,如果没有错误产生,那么程序的运行不受影响。
2,不依靠方法的返回值来报告错误是否产生。
3,采集集中的方式处理错误,能够根据错误种类的不同来进行对应的错误处理操作。
Java中常见的异常(括号内英文为对应异常处理类名称)。
算数异常(ArithmeticException):当算数运算中出现出现了除以零这样的运算就会出现这样的异常。
空指针异常(NullPointerException):没有给对象开辟内存空间却使用该对象时会出现空指针异常。
文件未找到异常(FileNotFoundException):当程序试图找到一个不存在的文件进行读写时将会引发该异常。经常是由于文件名给错,或者要存储的磁盘,CD-ROM等被移走,没有放入等原因造成。
数组下标越界异常(ArrayIndexOutOfBoundsException):对于一个给定的大小的数组,如果数组索引超过上限或者低于下限都造成越界。
内存不足异常(OutOfMemoryException):当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
Java的异常处理机制也秉承这面向对象的基本思想。在Java中,所有异常都是以类的类型存在。除了内置的异常类之外,Java也可以自定义异常类。此外Java的异常处理机制也允许自定义抛出异常。
*为何要处理异常
异常是在程序运行过程中发生的事件,例如除以零溢出,数组越界,文件找不到等,这些事件的发生将阻止程序的正常运行。在c语言中,可以通过使用if…else语句控制异常。同时,可通过被调用函数的返回值感知在其中的异常事件,并进行处理。然而使用函数返回的全局ErroNo(错误代码),仅能用来反应一个异常事件类型。这种异常监控模式异常繁琐,同一个异常或者错误如果多个地方出现,那么每个地方都要做相同处理。 Java通过面向对象的方法来处理异常。在一个方法的运行过程中如果发生了异常,则这个方法生成代表该异常的一个对象,并把他交给运行时系统。运行时系统寻找相应的代码来处理这一异常。我们把生成异常对象并把他提交给运行时系统的过程称之为异常的抛出(throw)。运行时系统在方法的调用栈中查找,从生成异常的方法进行回溯,直到找到相应的异常处理方法为止。这一过程称之为异常的捕获(catch)
简单的异常范例
public class Aaaa
{
public static void main(String args[])
{
int[] arr=new int[5]; //允许5个元素
arr[10]=7; //下标值超出范围
System.out.println("数组越界异常")
}
}
异常产生的原因在于数组的下标超出了最大允许范围,Java检测异常以后遍由系统抛出“ArrayIndexOutBoundsException”,用来表示错误原因,并停止运行程序。如果没有编写相应的处理异常的程序代码,Java的默认异常处理机制会先抛出异常,然后停止程序运行。
发现出现异常之后,异常语句之后代码不在执行,而是直接结束了程序运行。那么就表示此时程序是一种不健康的状态,为了保证程序出现异常之后,依然可以善始善终的完结,就需要引入异常处理操作。
异常的处理
在抛出异常之后,加上捕捉异常的程序代码,则可针对不同的异常做妥善处理,这个处理方法称为异常处理。
异常处理是由“try”,“catch”与“finally”等三个关键字所组成的程序块。语法如下:
try
{
要检查的语句
……
}
catch(异常类 对象名称)
{
异常发生时的处理语句;
}
[
catch(异常类 对象名称)
{
异常发生时的处理语句;
}
catch(异常类 对象名称)
{
异常发生时的处理语句;
}
……
]
[
finally
{
一定会运行到的程序代码;
}
]
Java提供了 try(尝试),catch(捕捉),finally(最终)等三个关键词来处理异常。这3个动作描述了异常处理的三个流程。
1,首先,我们把所有可能发生异常的j语句都放中欧一个try之后由{ }所形成的区块称为“try区块(try block)”。程序通过try{ }区块准备捕捉异常。try程序块若有异常发生,程序的运行便中断,并抛出“异常类所产生的对象”。
2,抛出的对象如果属于catch()括号内欲捕获的异常类,catch则会捕捉此异常,然后进入catch的块里继续运行。
3,无论try程序块是否捕捉到异常,或者捕捉到的异常是否与catch()括号内的异常相同,最终一定会运行finally块里的程序代码。
finally的程序代码块运行结束后,程序在回到try--catch--finally块之后继续执行。
上述可知,在异常捕捉的过程中至少做了两个判断:第一个是try程序块是否有异常产生,第二个是产生的异常是否与catch()括号内欲捕捉的异常相同。
注意:finally块可以省略,如果省略finally块,那么在catch()块运行结束后 程序将跳过try--catch块之后继续执行。
从上流程图可以看出,异常处理格式可以分为三类:try{ }…catch{ } 。 try{ }…catch{ }…finally{ } 。try{ }…finally{ }。
在处理各种异常,需要用到对应的“异常类”,“异常”指的是由程序抛出的对象所属的类。例如“ArrayIndexOutOfBoundsException”,就是众多异常类的一种。
异常处理的使用
class main
{
public static void main(String args[])
{
try
//检查这个程序块的代码
{
int arr[]=new int[5];
arr[10]=7; //在这里会出现异常
}
catch(ArrayIndexOutOfBoundsException ex)
{
System.out.println("数组超出绑定范围");
}
finally
//这个块的程序代码一定会执行
{
System.out.println("这里一定会执行");
}
System.out.println("main()方法结束!");
}
}
如果程序捕捉到了异常,则在catch括号内的异常类ArrayOutOfBoundsException之后生成一个对象ex,利用此对象可以得到相关信息。如下
class main
{
public static void main(String args[])
{
try
{
int[] arr=new int[5];
arr[10]=7;
}
catch(ArrayIndexOutOfBoundsException ex)
{
System.out.println("数组超出绑定范围");
System.out.println("异常:"+ex); //显示异常内容
}
System.out.println("main()方法结束");
}
}
//本例省略了finally{ }代码快。finally{ }代码快本意是程序运行的最后的“打完收工”步骤,非必要,省略。
catch( )视为专门捕获异常的方法,而括号内的内容可视为参数,而ex就是ArrayaindexOutOfException类所实例化的对象。对象ex接收到由异常类所产生的对象之后就输出catch代码块内代码。
如果想得到详细的异常信息,则需要使用异常对象的printStackTrace()方法。例如ex.printStackTrace();此方法可以给出更详细的信息,不仅包括异常的类型,还包括异常发生在哪个所属包,哪个所属类,哪个所属方法以及发生异常的行号。
通过初始化参数传递操作数字,使用多个catch捕获异常
class main
{
public static void main(String args[])
{
System.out.println("_____A,计算开始之前");
try
{
int[] arr=new int[5];
arr[0]=10;
arr[1]=5;
int result=arr[0]/arr[1];
System.out.println("_____B,除法计算结果+"+result);
}
catch(ArithmeticException ex)
{
ex.printStackTrace();
}
catch(ArrayIndexOutOfBoundsException ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("_____此处不管是否出错,都会执行");
}
System.out.println("____C,计算结束之后");
}
}
通过初始化参数传递操作数字 使用多个catch捕获异常
class main
{
public static void main(String args[])
{
System.out.println("_____A,计算开始之前");
try
{
int[] arr=new int[5];
arr[0]=10;
arr[1]=5;
arr[1]=0; //除数不能为0
arr[10]=7;
int result=arr[0]/arr[1];
System.out.println("_____B,除法计算结果+"+result);
}
catch(ArithmeticException ex)
{
ex.printStackTrace();
}
catch(ArrayIndexOutOfBoundsException ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("_____此处不管是否出错,都会执行");
}
System.out.println("____C,计算结束之后");
}
}
异常处理机制小结
当异常发生时,通过两种方法来处理,一种交给Java默认的处理机制做处理,但这种处理方式Java通常只能输出异常信息,接着终止程序运行。二种自行编写try—catch—finally块捕捉异常。自行编写程序代码块来捕捉异常最大好处是,可以灵活操作程序的流程,且可做最适当处理。
异常类的处理流程
异常可分为两大类:java.lang.Exception类和java.lang.Error类。这两大类均继承自java.lang.Throwable类。下图为Throwable类的继承关系图
习惯上将Error类与Exception类统称为异常类,但两者本质上还是不同的。Error类通常指的是Java虚拟机(JVM)出错,用户无法在程序里处理这种错误。Exception类包含了一般性的异常,这些异常通常在捕捉到之后便可做出妥善的处理,以确保程序继续运行。
异常处理流程:
1,如果程序之中产生了异常,那么会自动的由JVM根据异常的类型,实例化一个指定的异常类对象,而JVM的默认处理方式就是进行异常信息的输出,而后中断执行。
2,如果程序之中存在了异常,则会由try语句捕获产生的异常对象;然后将该对象与try之后的catch进行匹配,如果匹配成功,则使用指定的catch进行处理,如果没有匹配成功,则向后面的catch继续匹配,如果没有任何的catch匹配成功,则这个时候交给JVM执行默认处理。
3,不管是否有异常都会执行finally语句,如果没有异常,执行完finally,则会继续执行程序之中其他的代码,如果有异常没能够处理(没有一个catch满足),那么也会执行finally,但是执行完finally后,将默认交给JVM进行异常的信息输出,并且程序中断。
throws关键字
在Java标准库中的方法通常并没有处理异常,而是交由使用者处理,如判断整数数据格式是否合法的Integer.parseInt()方法就会抛出NumberFormatException异常
public static int parseInt(String s)throws NumberFormatException
就是这个“throws”关键字,如果字符串s中没有包含可解析的整数就会“抛给”上级调用方法。throws使用格式如下:
访问权限 返回值类型 方法名称(参数列表)throws 异常类
{
//方法体;
}
上面的格式分为两部分:一个b普通方法的定义,;方法后紧跟“throws 异常类”,它位于方法体{ }之前,用来检测当前方法是否异常,若有,则将该异常提交给直接使用这个方法的方法。
关键字throws的使用
public class Main
{
public static void main(String args[])
{
int[] arr=new int[5];
try
{
setZero(arr,10);
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("数组超出绑定范围!");
System.out.println("异常:"+e);
}
System.out.println("main()方法结束");
}
private static void setZero(int[] arr,int index)throws ArrayIndexOutOfBoundsException
{
arr[index]=0;
}
}
throw关键字
之前所有异常类对象全部是由JVM自动实例化的,想要自己进行异常类对象的实例化操作,自己手工抛出异常,需要用throw关键字完成。与throws不同的是,可直接使用throw抛出一个异常,抛出时直接抛出异常类的实例化对象即可。throw语句格式:
throw 异常类型的实例;
执行这条语句时,将会“引发一个指定类型的异常,也就是抛出异常。
关键字throw的使用
class throwDemo
{
public static void main(String args[])
{
try
{
//创建一个匿名的ArrayIndexOutOfBoundsException类型的异常对象,并使用关键字throw抛出。引发运行期异常,并输出异常信息
throw new ArrayIndexOutOfBoundsException("\n我是个性化的异常信息:\n数组下标越界"); //抛出异常的实例化对象
}
catch(ArrayIndexOutOfBoundsException ex)
{
System.out.println(ex);
}
}
}
异常处理的标准格式
关键字throw和throws混合使用
class throwDemo
{
public static void main(String args[])
{
int[] arr=new int[5];
try{
setZero(arr,10);
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("异常:"+e);
}
System.out.println("main()方法结束");
}
private static void setZero(int[] arr,int index)throws ArrayIndexOutOfBoundsException
{
System.out.println("方法setZero开始");
try{
arr[index]=0;
}
catch(ArrayIndexOutOfBoundsException ex)
{
throw ex;
}
finally{
System.out.println("方法setZero结束");
}
}
}
RuntimeException类
class aaaaa
{
public static void main(String args[])
{
String str="123";
int i=Integer.parseInt(str);
System.out.print(i*2);
}
}
上面代码一般情况运行没有问题,代码中没有任何检测异常语句。Integer类中的parseInt()方法定义。
public static int parseInt(String s) throws NumberFormatException;
通过查看parseInt方法原型,可以发现,parsrInt()使用了throws抛出一个异常。NumberFormatException类继承自RuntimeException类,在Java中明确规定对于RuntimeException的异常类型可以有选择性地来进行处理,如果不处理则出现异常时交给JVM默认处理。常见的RuntimeException类型的异常有NumberFormatException,ClassCastException,NullPointerException,ArithmeticException,ArrayIndexOutOfBoundsException
Exception强制性要求用户必须处理
RuntimeException是Exception的子类,由用户选择是否进行处理。
编写自己的异常类
Java本身已经提供了大量的异常类型,开发中这些异常类型可能不能满足于全部需求,为了处理各种异常,Java可通过继承的方式运行用户编写自己的异常类。因为所有可处理的异常类均继承自Exception类,因此自定义异常类也不例外。语法如下:
class 异常类名称 extends Exception
{
…
}
自定义自己的异常类
class throwDemo
{
public static void main(String args[])
{
try{
throw new MyException("自定义异常,仅为测试演示");
}
catch(MyException e){
System.out.println(e);
}
}
}
class MyException extends Exception
{
public MyException(String msg){
super(msg); //调用Exception类的构造方法,存入异常信息
}
}
1,异常类型最大父类是Throwable类,其子类分两大类,Exception和Error。Exception表示程序可处理的异常。Error表示JVM错误,一般无需程序员自己处理。
2,RuntimeException类是Exception的子类,Exception定义了必须处理的异常,而RuntimeException定义的异常可以选择性处理。