------- android培训、java培训、期待与您交流! ----------
一、异常的概念
顾名思义就是不正常,在Java中的异常就是程序中出现的不正常的情况。
我们知道在Java面对对象的编程思想中,所有事物都通过类的形式描述,并封装成对象,而异常是一种现象,也可以被类描述,然后可以封装成一个异常对象其实异常就是Java对不正常情况进行描述后的对象体现。
异常示例:
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
try //捕获异常
{
//可能出现异常的代码
int x = d.div(3,0);
System.out.println("x="+x);
}
catch (Exception e)//传递异常信息 并处理
{
//返回异常的简短描述
System.out.println(e.toString());
//返回异常的详细信息
System.out.println(e.getMessage());
//返回异常名称,异常信息,异常出现的位置,其实jvm默认的异常处理机制,就是在调用printStackTrace方法。
e.printStackTrace();
System.out.println("除数不能为零");
}
System.out.println("over");
}
}
class Demo
{
int div(int a,int b)
{
return a/b;
}
}
二、异常的分类
1.在Java中将系统异常和自定义异常。
系统异常:
就是Java中已经定义好一些类,如空指针异常、数组角标越界异常等,并且已形成一个异常体系
自定义异常:
就是我们自己定义的对一些异常情况的描述,但必须继承系统的异常类才能使用,就是加入所谓的异常体系才会被系统认为是异常类。自定义的异常类可以使用父类已经定义好的功能,并且可以将异常信息传递给父类的构造函数,交给父类解决。
2.异常体系
我们都知道在Java中,事物都可以被描述封装成对象。
异常对于Java来说也是可以描述的,因此也可以抽象成类并封装,这种类我们成为异常类。
在现实生活中,异常有很多中,因此异常类也有很多种,在Java中对这些异常类中的共性内容不断向上抽取,因此就形成了一个可观的异常体系。
异常体系的成员
Throwable
|--Error
|--Exception
|--RuntimeException
Throwable从字面意思理解就是可抛的,这是所有异常的父类,所有的异常类都有可抛的特性。
Throwable:
无论是Error,还是Exception问题,问题发生就应该可以抛出,让调用者知道并处理。
该体系的特点就在于Throwable及其所有的子类都具有可抛性。
3.可抛性到底指的是什么呢?throws throw
怎么体现可抛性呢?凡是可以被这两个关键字所操作的类和对象都具备可抛性。
1).一般不可处理的 Error
特点:是同Jvm抛出的严重性的问题。
通常出现重大问题如:运行的类不在在或者内存溢出等。
这种问题发生一般不针对性处理,直接修改程序。
错误:通常是不编写代码对其进行针对处理。
2).可以处理的。Exception
处理Exception异常有两种方法:
一是:在运行时运行出现的一些情况,可以通过 try catchfinally
二是:通过throws在函数上声明。(如果函数内throw异常,那么函数就必须声明)
异常体系的特点
异常体系中的所有类以及建立的对象都具备可抛性,也就是说可以被throw和throws关键字所操作,只有异常体系具备这个特点。
4.关键字Throw和throws
Throw和throws用于操作异常
Throw和throws的区别
throw定义在函数内,用于抛出异常对象。
throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开。
5.处理异常(Exception)的几种格式:
格式一:
try{
可能发生异常的代码;
}
catch(接收捕获异常类的对象){
处理代码;
}
格式二:
try{
可能发生异常的代码;
}
fianlly{
一定要执行的语句;(通常用于关闭资源)
}
格式三:
try{
可能发生异常的代码;
}
catch(捕获异常类的对象 ){
处理代码;
}
finally{
一定要执行的语句;(通常用于关闭资源)
}
注意:
1.finally中定义的通常是 关闭资源代码,如数据库的连接、服务器的访问,因为资源必须释放。
2.finally只有一种情况不会执行。当执行到System.exit(0);fianlly不会执行。
6.异常的选择:
当抛出的异常是调用者误操作完成的,那么继承RuntimeException类,如果该异常的发生,就让该程序停掉。
一般情况下继承的都是Exception异常。
7.异常有两种:
编译时异常:
该异常在编译时,没有处理(没有抛出也没有try),编译失败
运行时异常(编译时不检测):
在编译时的不需要处理,编译器不检查
该异常的发生,建议不处理,让程序停止,需要对代码进行修正
注意:
当函数内有throw抛出异常对象,并未进行try处理。必须要在函数上声明,否则编译失败
Exception有一个特殊的子类,RuntiimeException。
也就是说,函数内如果抛出的RuntimeException异常,函数上可以不用声明。
注意:
如果Exception在内部被解决,比如内部catch(捕获)并对异常进行了处理,则该方法不用声明异常。
记住一点,catch是用于处理异常,如果没有catch就代表异常没有被处理。
如果该异常是检测,可以没有catch语句。
当然:如果抛出的是多个异常,就要有几个catch,也有简单的做法,直接抛父类异常Exception
异常小练习:
/*
毕老师用电脑上课。
开始思考上课中出现的问题。
比如问题是
电脑蓝屏。
电脑冒烟。
要对问题进行描述,封装成对象。
可是当冒烟发生后,出现讲课进度无法继续。
出现了讲师的问题:课时计划无法完成。
*/
//描述异常类 蓝屏
class LanpingException extends Exception
{
LanpingException (String message)
{
super(message);
}
}
//描述异常类 冒烟
class MaoYanException extends Exception
{
MaoYanException(String message)
{
super(message);
}
}
//描述异常类 当冒烟发生后,出现讲课进度无法继续
class NoPlanException extends Exception
{
NoPlanException(String message)
{
super(message);
}
}
//定义一个电脑类
class Computer
{
//定义一个状态判断是否异常
private int state = 3;
public void run()throws LanpingException,MaoYanException
{
if(state==2)
throw new LanpingException("电脑蓝屏了");
if(state==3)
throw new MaoYanException("电脑冒烟了");
System.out.println("开机");
}
public void reset()
{
//状态初始化
state = 1;
System.out.println("重启");
}
}
//定义老师类
class Teacher
{
private String name;
private Computer cmpt;
Teacher(String name)
{
this.name=name;
cmpt = new Computer();
}
void jiangKe()throws NoPlanException
{
try
{
cmpt.run();
}
catch(LanpingException e)
{
cmpt.reset();
}
catch(MaoYanException e)
{
test();
//当冒烟异常出现 无法处理继续抛出异常
throw new NoPlanException("电脑冒烟了,课时无法继续"+e.getMessage());
}
System.out.println("讲课");
}
void test()
{
System.out.println("做题");
}
}
class ExceptionTest1
{
public static void main(String[] args)
{
//创建毕老师对象
Teacher t = new Teacher("毕老师");
try
{
t.jiangKe();
}
catch (NoPlanException e)
{
System.out.println(e.toString());
System.out.println("换老师或者放假");
}
}
}
8.异常处理的原则:
1) 函数内容如果抛出需要检测的异常,那么函数上必须要声明。
否则必须在函数内用try catch捕捉,否则编译失败。
2) 如果调用到了声明异常的函数,要么try catch要么throws,否则编译失败。
(如果调用的函数抛出异常,那么调用者可以try catch也可以throws)
(如果调用的是复写父类的函数抛出异常,那么调用者只能抛出父类同样的异常,或者父类异常的子集)
3) 什么时候catch,什么时候throws 呢?
功能内容可以解决,用catch。
解决不了,用throws把异常告诉调用者,由调用者解决。
4) 一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性的处理。
内部有几个需要检测的异常,就抛几个异常,抛出几个,就对应有几个catch。
5) 抛到最后抛给谁才是个头呢?答案是抛到虚拟机才是头。
9.fianlly 特殊之处:
finally语句中定义的是一定要执行的语句,通常用于关闭资源。(因为资源必须释放)
finally除非遇到System.exit(0);也是就虚拟机退出才不会执行。
子类覆盖父类时对异常处理的注意事项:
1)如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2)如果父类方法抛出多个异常,那么子类再覆盖该方法时,只能抛出父类异常的子集。
(也就是父类如果抛多个异常,那么我们不能直接抛Exception异常。)
(如果抛一个异常的时候,是可以抛父类异常的)
3)如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
4)如果子类方发发生了异常,就必须要进行try处理,绝对不能抛。
5)如果在子类的覆盖方法确实需要抛出非父类的异常或者该异常的子类,则必须在内部解决。
10.自定义异常
定义类继承Exception或者RuntimeException
(其实我们这样也是用面向对象思考问题,把我们程序设计中可能出现的问题进行了封装。)
1. 为了让该自定义类具备可抛性
2. 让该类具备操作异常的共性方法
3. 当要自定义异常的信息时,可以使用父类已经定义好的功能,异常信息传递给父类的构造函数。
11.异常转换:
如果该异常处理不了,但并不属于该功能出现的异常,可以将异常转换后,再抛出和该功能相关的异常
或者异常可以在内部处理,但需要将异常缠上本功能相关的内容提供出去,调用者知道,并处理,也可以将捕获的异常处理后,转换为新的异常。
异常小练习:
/*
有一个圆形和长方形。
都可以获取面积。对于面积如果出现非法的数值,视为是获取面积出现问题。
问题通过异常来表示。
现有对这个程序进行基本设计。
*/
//定义异常类 因为出现非法值 我们无法处理 让调用者出来 所以继承RuntimeException
class NoValueException extends RuntimeException
{
NoValueException(String Message)
{
super(Message);
}
}
//将求面积的方法向上抽取为一个接口
interface MianJi
{
public abstract void getarea();
}
//定义圆的类
class Corcle implements MianJi
{
final static double PI = 3.14;
private double r;
Corcle(double r)
{
//判断值是否非法 并且抛出异常对象
if(r<=0)
throw new NoValueException("半径为负数了");
this.r = r;
}
public void getarea()
{
System.out.println("area="+PI*r*r);
}
}
//定义长方形类
class Rec implements MianJi
{
private int height;
private int top;
Rec(int height,int top)
{
//判断值是否非法 并且抛出异常对象
if(height<=0||top<=0)
throw new NoValueException("出现非法值了");
this.height=height;
this.top=top;
}
public void getarea()
{
System.out.println("area="+height*top);
}
}
class ExceptionTest2
{
public static void main(String[] args)
{
//求圆的面积
Corcle c = new Corcle(-2);
c.getarea();
//求长方形面积
Rct r = new Rct();
r.getarea();
}
}