错误是我们人生中必不可少的一种美,是的,同时是很让人不爽的。而在java程序中也会出现这样或那样不爽的问题。如果程序中存在错误,或者由于一些外部等不良情况发生了,这就会使得用户的数据受损。所以,一个好的程序,应该尽量避免此类情况的发生,或者必须“治愈这种病”,也就是对程序的异常进行处理。所以应该做到这样几点:
1、将可能发生的错误通知给用户
2、发生错误的时候,应该讲已操作的数据进行保存其结果
3、提供给用户适当的途径结束程序。
4、程序员还需定期查看程序异常,并进行修正
一、异常概述:
1、异常是指程序在运行时出现的不正常情况
2、异常由来:问题是现实生活中的事物,也可以通过java类的形式进行描述,并封装成对象。因为异常也可以被抽取,形成一个体系,并由一个个具体的实例组成,也是一个个对象。
3、程序可能出现的错误或问题
a.用户输入错误导致的异常:如用户不正常使用程序,输入一些非法参数
b.设备硬件等发生的错误:如硬盘损坏等
c.物理限制:如存储空间不足等
d.代码错误:在程序编写的方法可能不正确,返回错误参数等。
二、异常体系:
1、异常分为两种:严重的和非严重的异常。
a.严重的异常:java通过Error类进行描述;一般不编写针对性的代码进行处理
b.非严重异常:java通过Exception类进行描述,可使用针对性的代码对其处理
共性:
a.都含有不正常情况的信息,引发原因等
b.都是通过抽取形成了超类Throwable
·RuntimeException:由程序错误导致的异常。
·IOException:程序本身没问题,由I/O错误导致的异常。
规则:
若出现RuntimeException异常,一定是自己的问题。
2、Exception中异常划分:
1)编译时被检测异常(编译javac时会检查代码):该异常在编译时,若未处理(没有抛也没有try),编译失败,该异常被标识,代表可被处理。
2)运行时异常(编译时不检查)-RuntimeException:编译时,无需处理,编译器不检查该异常发生,建议不处理,让程序停止,需对代码进行修正。
RuntimeException:若在函数内抛出该异常,函数上可不用声明,也可通过,若在函数上声明了该异常,调用者可不用进行处理,编译也可通过。
可不在函数上声明,因为无需让调用者处理。当异常发生时,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
3、继承的异常简介:
1)继承于RuntimeException的异常情况:
·错误类型转换:ClassCastException
·空指针异常:NullPointerException
·数组访问越界:IndexOutOfBoundsException
2)非继承于RuntimeException的异常情况:
·试图在文件尾部读取数据
·试图打开一个错误格式的URL
·试图根据给定的字符串查找class对象,而此字符串表示的类不存在
三、异常的处理:
异常处理的任务:将控制权从错误产生的地方转移给能处理错误这种情况的错误处理器。
若函数上声明了异常,调用者需进行处理,处理方法可以throw,可以try。
1、对捕获的异常对象进行常见方法的操作:
trrows Exception:抛出异常
try-catch-finally:捕获异常 ---- java中提供了特有的语句进行处理。
String getMessage();获得异常信息
2、throw和throws的用法:
1)throw:定义在函数内,用于抛出异常对象。注:throw单独存在时,下面不要定义语句,因为执行不到,编译失败。
2)throws:定义在函数上,用于跑出异常类,可抛多个,用逗号隔开。
注:当函数内有throw抛出异常对象,必须给出对应的处理动作,若并未进行try处理,需在函数上声明,否则编译失败。
一般函数出现异常,需在函数上声明,但RuntimeException除外,若在函数内抛出此异常,函数上可不声明。
3、异常处理语句:
结合方式:
① try-chatch ②try-finally ③try-catch-finally
格式:
try
{
//需要被检测的代码;
}
catch (异常类 变量)
{
//理异常的代码;(处理方式)
}
finally
{
//一定会执行的语句;
}
在函数上声明异常:便于提高安全性,让调用者进行处理,若不处理,则编译失败
注:finally中定义的通常为:关闭资源代码,因为资源必须被释放。
有一种情况不会执行finally,即出现System.exit(0);这条语句,后面的finally不会执行,因为这个代表系统退出吗,JVM结束。
try {
...
} catch () {
//......
System.exit(0);
} finally {
...
}
4、多异常的处理:
1)声明异常时,建议声明更为具体的异常,这样处理更具体。
注:抛出几个具体的问题处理时,就具体处理哪些问题,而不是再加上catch(Exception e){...}让JVM自己将问题解决后再继续运行,那么调用者将不知道发生了什么问题。
2)原则:
对方声明几个异常,就对应几个catch块,不要定义多余catch,若多个catch块中的异常出现继承关系,父类异常catch块,放最下面(最大,处理更多)。
3)建议:
在进行catch处理时,catch中一定要定义具体处理方式,不要简单的定义一句:e.printStatckTrace();,也不要简单的打印一句。
遇到异常要怎么处理呢?常规做法是不打印异常信息,因为即时打印了,用户也无法解决掉,最好是将问题或信息记录下来,并存储为异常日志文件,便于程序员管理查阅,并及时修正代码,管理程序。
四、自定义异常:
1、概述:
因为项目中会出现特有问题,而这些问题并未被java所描述并封装成对象,所以这些特有问题可按java中对问题封装的思想,将特有问题进行定义的异常封装。
2、继承Exception或RuntimeException的原因:
1)异常体系有一个特点:异常类和异常对象都被抛出,他们都具有可抛性。这个可抛性是Throwable这个体系单独有的特点,只有此体系中的类和对象才可被throws和throw操作。
2)为了让该类具备操作异常的共性方法。
3、定义异常信息:
由于父类中把异常信息的操作完成了,所以子类只需要在构造函数时,将异常信息传递给父类,通过super语句,则可直接用getMessage方法,自动自定义的异常。
class MyException extends Exception
{
MyException(String message)
{
super(message);
....
}
}
自定义异常时,若该异常的发生无法继续进行运算,就让自定义异常继承RuntimeException。
五、异常的好处:
1、将问题进行封装
2、将正常流程代码和问题处理代码相分离,便于阅读。
六、异常处理原则
1、处理方式:throw或throws
2、调用到抛出异常的功能时,抛几个,处理几个,一个try可以对应多个catch
3、多个catch,父类catch放在最下面。
4、catch内需要定义针对性的处理方式,不要定义printStackTrace,输出语句也不要不写,当捕获到异常,本功能处理不了时,可继续在catch中抛出
若该异常处理不了,但不属于该功能出现的异常,可以讲异常转换后,再抛出或可处理异常,但需要将异常产生的和本功能相关的问题提供出去,让调用者知道并处理,也可以将捕获的异常处理后转换为新异常。如汇款的例子。
示例:
try
{
throw new AException();
}
catch (AException e)
{
//方式一
throw e;
//方式二
...处理AException语句
throw new BException();
}
七、异常注意事项:
1、在子父类覆盖时:
1)子类抛出的异常须为父类异常的子类或子集
2)若父类或接口无异常抛出,子类覆盖的方法出现异常,只能try,不能抛。
2、异常机制:
1)只有在异常情况下使用异常,不可随处都用
2)不能过分的细化异常,即将正常程序和错误处理分开。这样也更清晰。
3)充分使用异常体系结构:Exception的体系很庞大,不要抛出由于逻辑错误造成的异常,要将一种异常转换成另一种更加适合的异常时,就需要抛出新异常,让可处理此异常的调用者处理。
4)不要压制异常:java中存在着强烈关闭异常的倾向。即使很难出现异常情况时,也要考虑异常的发生,并声明后将其关闭。
5)在检查错误时,要对异常“苛刻”一些,异常越是具体越好,将异常的范围缩小处理(或抛出)。
6)不要保留异常,要敢于传递异常:传递异常比捕获异常更好,让高层次的方法通告用户发生的错误,或者放弃不成功的命令更加合适。
原则:对于异常:早抛出,晚捕获。
参考例子:
/*
毕老师用电脑讲课
开始思考上课中出现的问题:如:电脑蓝屏、电脑冒烟
描述问题,封装成对象
可当冒烟发生后,出现讲课无法继续。
出现了讲师的问题:课程计划无法完成
*/
//自定义蓝屏异常
class LanPingException extends Exception {
LanPingException(String messgae)
{
super(messgae);
}
}
//自定义冒烟异常
class MaoYanException extends Exception
{
MaoYanException(String messgae)
{
super(messgae);
}
}
//自定义课时无法继续异常
class NoPlanExceptioon extends Exception
{
NoPlanExceptioon(String messgae)
{
super(messgae);
}
}
class Computer
{
//state为1时,正常;为2时,蓝屏;为3时,冒烟
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("run");
}
//重启,恢复蓝屏异常
public void reset()
{
state = 1;
System.out.println("reset");
}
}
//创建教师类
class Teacher
{
private String name;
Computer comp;//讲课要用电脑,初始化老师时就产生这个
Teacher(String name)
{
this.name = name;
comp = new Computer();
}
//定义上课方法
public void prelect()throws NoPlanExceptioon//冒烟了就不要抛MaoYanException了,因为这个异常老师解决不了,直接抛出老师熟悉的异常
{
try
{
comp.run();
}
catch (LanPingException l)
{
comp.reset();
}
catch (MaoYanException m)//注意这里
{
test();
throw new NoPlanExceptioon("课时无法继续" + m.getMessage());//再次抛出异常,抛给熟悉该异常的人
}
System.out.println("讲课");
}
public void test()
{
System.out.println("练习");
}
}
//测试
class ExceptionTest
{
public static void main(String[] args)
{
Teacher t = new Teacher("毕老师");
try
{
t.prelect();
}
catch (NoPlanExceptioon n)
{
System.out.println(n.toString());
System.out.println("换老师或放假");
}
}
}
/*
有个圆形和长方形,都可以获取面积,对于面积若出现非法数值,是为获取面积出问题
问题通过异常来表示
*/
//创建输入值错误的异常
class NoValueException extends RuntimeException//对问题名称的描述,更具体
{
NoValueException(String message)
{
super(message);
}
}
//创建接口,抽取获取面积方法
interface ShapeArea
{
void getArea();
}
//创建获取长方形面积的类
class Rec implements ShapeArea
{
private int len,wid;
//此处声明了,就会将问题抛给主函数中解决
Rec(int len,int wid)throws NoValueException
{
if (len<=0 || wid<=0)
throw new NoValueException("出现非法值了");
this.len = len;
this.wid = wid;
}
public void getArea()
{
System.out.println(len*wid);
}
}
//创建获取圆形面积的类
class Circle implements ShapeArea
{
private int rad;
private static final double PI = 3.14;
//此处未声明,当调用该函数,发生异常时会直接结束程序,并打印具体的异常信息
Circle(int rad)
{
if (rad<=0)
throw new NoValueException("出现非法值了");
this.rad = rad;
}
public void getArea()
{
System.out.println(rad*rad*PI);
}
}
//测试
class Exception
{
public static void main(String[] args)
{
//方式一:出现异常时,信息不具体
try
{
Rec r= new Rec(-3,4);
r.getArea();
}
catch (NoValueException e)
{
System.out.println(e.toString());
}
System.out.println("OVER");
//方式二:出现异常时,信息更具体
Circle c = new Circle(-8);
c.getArea();
}
}