异常:就是程序在运行时出现不正常情况。
比如说访问一个长度为3的数组中的第4个元素就会抛出角标越界异常。
java语言中的异常是通过一个对象来表示的,程序运行时抛出的异常,实际上就是一个异常对象。这个对象中封装了错误信息,还提供了一些处理方法,如getMessage()方法获取异常信息。
异常有的需要进行捕获处理或声明抛出,这种异常称为受检查异常。
而有的是有java虚拟机自动进行捕获处理,这种异常称为运行时异常。
异常的划分:
对于问题的划分:两种:一种是严重的问题,一种是非严重的问题。
对于严重的,java通过Error类进行描述。
对于Error一般不编写针对性的代码对其进行处理。
对于非严重的,java通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
无论Error或者Exception都具备一些共性内容,比如:不正常情况信息,引发原因等。
Exception类又可以分为两种异常类型:
1,RuntimeException异常。
2,检查异常。
RuntimeException是运行时异常,是程序员编写的程序中的错误导致的。它必须使用异常处理机制来处理,这类异常
在编译时是可以通过的,只是在运行时有java虚拟机来抛出。
常见的RuntimeException异常有:算术异常ArithmeticException,空指针异常NullPointerException,
角标越界异常IndexOutOfBoundsException,类型转换异常ClassCastException等等。
对于检查异常必须通过try...catch捕获或由throws抛出,否则编译出错。
常见的检查异常有:未找到相应类异常ClassNotFoundException,输入输出异常IOException,
文件未找到异常FileNotFoundException,访问被拒绝时抛出的异常IllegalAccessException
等等。
2,异常的处理
异常产生后,若不做任何处理,则程序就会被终止,为了保证程序有效的执行,就需要对产生的异常进行相应处理。
异常有两种处理方式:
1,在当前方法中进行捕获然后处理异常。这里要用到try,catch,finally三个关键字。
2,通过throw和throws将异常向上抛出,由方法的调用者来处理。
使用try...catch语句:
try
{
需要被检测的代码
}
catch(异常类 异常对象)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
记住:catch是用来处理异常的,如果没有catch就代表异常没有被处理过,如果该异常是检测时异常那么必须声明catch。
try语句块中的代码可能同时存在多种异常,那么到底捕获的是哪一种类型的异常,是由catch语句中的“异常类”参数来指定的。
catch语句类似于方法的声明,包括一个异常类型和该类的一个对象:
异常类:必须是Throwable类的子类,用来指定了catch语句要捕获的异常。
异常类对象:可以在catch语句块中被调用,例如调用对象的getMessage()方法获取对异常的描述信息。
比如声明一个方法将a/b,如果b=0的话,这个方法就会抛出ArithmeticException异常。所以在应用这个方法时就可以通过try...catch语句来捕获该异常,从而进行相应的异常处理。
异常类对象:可以在catch语句块中被调用,例如调用对象的getMessage()方法获取对异常的描述信息。
比如声明一个方法将a/b,如果b=0的话,这个方法就会抛出ArithmeticException异常。所以在应用这个方法时就可以通过try...catch语句来捕获该异常,从而进行相应的异常处理。
代码演示:
class Demo
{
int div(int a,int b)throws Exception
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
try{
int x=d.div(9,0); //抛出ArithmeticException异常
System.out.println("x="+x);
}catch(Exception e){//捕获ArithmeticException异常
System.out.print("被除数为零 ");
System.out.print(e.getMessage());
}
System.out.println("Over");
}
}
对捕获到的异常对象进行常见方法操作。
String getMessage(); 获取异常信息。
toString();获取异常类名和异常信息,返回字符串。
在try…catch语句中,可以同时存在多个catch语句块。
一般格式为:try{
可能产生异常的代码
}catch(异常类1 异常对象){
异常1处理代码
}catch(异常类2 异常对象){
异常2处理代码
}
代码中的每个catch语句块都用来捕获一种类型的异常。若try语句块中的代码发生异常,则会由上而下依次来查找能够捕获该异常的catch语句块,并执行该catch语句块中的代码。
可能产生异常的代码
}catch(异常类1 异常对象){
异常1处理代码
}catch(异常类2 异常对象){
异常2处理代码
}
代码中的每个catch语句块都用来捕获一种类型的异常。若try语句块中的代码发生异常,则会由上而下依次来查找能够捕获该异常的catch语句块,并执行该catch语句块中的代码。
对多异常的处理:
1,声明异常时,建议声明更为具体的异常,这样可以处理的更具体。如:数学异常用ArithmeticException。
每个异常之间用逗号隔开即可,如:Throws ArithmeticException,ArithmeticException。
2,对方有几个异常就用几个 catch块,不要定义多余的catch块。
如果多个catch块中的异常出现继承关系,父类异常catch块放在下面。
例如:
try{
int x=d.div(9,0); //抛出ArithmeticException异常
System.out.println("x="+x);
}catch(ArithmeticException e){ //捕获异常类Exception的子类异常
System.out.print(e.getMessage());
}catch(Exception e){ //捕获ArithmeticException异常
System.out.print(e.getMessage());
}
建议在进行catch处理时,catch中一定要定义具体的处理方式,不要简单的定义一句e.printStackTrace(),
也不要简单的就书写一条输出语句。
异常-finally
finally子句需要与try…catch语句一同使用,不管程序中有无异常发生,并且不管之前的try…catch是否顺利执行完毕,最终都会执行finally语句块中的代码,这使得一些不管在任何情况下都必须执行的步骤被执行。
例如:
try{
int x=d.div(9,0); //抛出ArithmeticException异常
System.out.println("x="+x);
}catch(Exception e){ //捕获ArithmeticException异常
System.out.print(e.getMessage());
}finally{ //不管程序有无异常该语句都会执行
System.out.println("运算结束");
}
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作,要么在内部try catch处理,要么在
函数上声明让调用者处理。
一般情况下,函数内部出现异常,函数上需要声明。
如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了,所以子类只要在构造时将异常信息传递给父类通过super语句,
那么就可以直接通过getMessage方法获取自定义的异常信息。
使用throws关键字抛出异常:
如果某个方法可能会发生异常,但不想在当前方法中来处理这个异常,那么可以将该异常抛出,然后在调用该方法的代码中捕获该异常并进行处理。抛出多个异常时用逗号隔开
throws和throw的区别:
throws使用在函数上,throw使用在函数内。
throws后面跟的是异常类,可以跟多个,用逗号隔开;throw后跟的是异常对象。
自定义异常:
必须是自定义类继承Exception。如,
class AException extends Exception{
AException(String message){
super(message);
}
}
继承exception原因:
异常体系有一个特点,因为异常类和异常对象都需要被抛出,他们都具备可抛性,这个可抛性是Throwable
这个体系中独有特点。只有这个体系中的类和对象才可被throws和throw操作。
异常的细节:
1,RuntimeException以及其子类如果在函数中被throw抛出,可以不用在函数上声明。
2,一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类。
3,如果父类抛出多个异常,那么重写(覆盖)方法必须抛出那些异常的一个子集,不能抛出新的异常。
2,一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类。
3,如果父类抛出多个异常,那么重写(覆盖)方法必须抛出那些异常的一个子集,不能抛出新的异常。
4,如果被覆盖的方法没有抛出异常,子类也不允许抛出异常。如果子类中真的出现异常,只能在子类方法内进行try处理,绝对不允许throws声明。如果处理不了可以选择抛出运行时异常。
自定义异常时:如果该异常的发生无法在继续进行运算,就让自定义异常继承RuntimeException。
自定义异常大体可以分为以下几个步骤:
1,创建自定义异常类。
2,在方法中通过throw抛出异常对象。
3,若在当前抛出异常的方法中处理异常,可使用try…catch语句捕获并处理;否则在方法的声明处通过throws指明要抛出的异常。
4,在出现异常的方法调用代码中捕获并处理异常。
如果自定义的异常类继承自RuntimeExeption异常类,在步骤 3 中,可以不通过throws指明要抛出的异常。
2,在方法中通过throw抛出异常对象。
3,若在当前抛出异常的方法中处理异常,可使用try…catch语句捕获并处理;否则在方法的声明处通过throws指明要抛出的异常。
4,在出现异常的方法调用代码中捕获并处理异常。
如果自定义的异常类继承自RuntimeExeption异常类,在步骤 3 中,可以不通过throws指明要抛出的异常。
异常在子父类覆盖中的体现:
1,子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类。
如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3,如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生了异常,就比须要进行try处理,绝对不能抛。
class NoOilException extends Exception
{
NoOilException(String msg)
{
super(msg);
}
}
class FlatTireException extends Exception
{
FlatTireException(String msg)
{
super(msg);
}
}
class StopPlanException extends Exception
{
StopPlanException(String msg)
{
super(msg);
}
}
class Car
{
int state = 3;
public void run() throws NoOilException, FlatTireException
{
if(state==2)
throw new NoOilException("车子没油了,找地方加油···");
if(state==3)
throw new FlatTireException("车子爆胎了");
System.out.println("汽车启动,旅行中···");
}
public void reset()
{
System.out.println("重新启动车子,继续旅行···");
}
}
class Tourism
{
private Car c = new Car();
public void travel() throws StopPlanException
{
try
{
c.run();
}
catch(NoOilException e)
{
c.reset();
}
catch(FlatTireException e)
{
throw new StopPlanException("旅游暂时停止"+" "+e.getMessage());
}
System.out.println("旅游");
}
}
public class ExceptionTest
{
public static void main(String[] args)
{
Tourism t = new Tourism();
try
{
t.travel();
}
catch(StopPlanException e)
{
System.out.println(e.toString());
System.out.println("暂时下车休息,打电话找人修车");
}
}
}