导读:异常概述,处理(try-catch), 常见方法操作,多异常的处理,异常声明throws, 自定义异常,throw和throws的区别,RuntimeException,异常练习(电脑让课),异常finally
1、异常—概述
l 异常:就是程序在运行时出现不正常情况,并且在不正常处程序结束了。
l 异常由来:问题也(一个问题产生后,它即有问题的原因,又有问题的现象,还有问题的信息)是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。异常就是用面向对象的方法,把产生的问题进行描述,并对其进行对象的封装成。其实就是java对不正常情况进行描述后的对象体现。
l 对于问题的划分:两种:一种是严重的问题,一种非严重的问题。
Ø 对于严重的,java通过Error类进行描述(对于Error一般不编写针对性的代码对其进行处理)。
Ø 对与非严重的,java通过Exception类进行描述(对于Exception可以使用针对性的处理方式进行处理)。
l 无论Error或者Exception都具有一些共性内容。比如:不正常情况的信息,引发原因等。(向上抽取,形成体系)
l Throwable (它是java中所有错误或异常的超类,定义了体系的共性内容)
|--Error 通常出现重大问题如:运行的类不存在或者内存溢出等。不编写针对代码对其处理
|--Exception java为了便于阅读性,将父类的名字做为子类的后缀名
方法:
getCause() //获取原因
getMessage() //获取异常或者错误的信息
printStackTrace()//打印这些信息。获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void
NoClassFoundErrorr找不到对应的class或者java文件
ArithmeticException (4/0)
2、异常的处理(try-catch)
l java 提供了特有的语句进行处理。
try //由三部分代码块组成,这三部分是一个整体。
{
需要被检测的代码;(检测到异常把它丢给了catch)new ArithmeticException()
}
catch(异常类变量)//catch接收到异常对象。Exception e = newArithmeticException(); 代码跳到catch中去执行。
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
l class Demo
{
int div(int a,int b) //产生了ArithmeticException并把它封装成了一个对象:newArichmeticException(); ,再把这个问题抛给调用它的主函数。如果主函数中没有try-catch,主函数没办法处理问题,会把这个问题给JVM,JVM调用默认处理机制,导致程序停止。
{
return a/b;
}
}
l Java虚拟机认识异常,因为这是它定义的。当引发了它所熟悉的状况,就给你处理这是因为Java虚拟机内部有一个异常的处理机制。只要程序出现问题,就不再运行了。
3、对捕获到的异常对象进行常见方法操作。
l String getMessage():获取异常信息[System.out.println(e.getMessage());]。
l System.out.println(e.getMessage());打印的更全面一点即带有打印的信息,也带有打印的名字。(异常信息:异常名字)
l e.printStackTrace();无返回值,不要放在打钱语句中输出。它最全面(异常信息,异常名字,异常出现的位置)。其实jvm默认的异常处理机制,就是在调用printStackTrace方法。打印异常的堆栈的跟踪信息。
4、异常声明throws
l 某功能是别人编写的,一定要做try-catch处理吗?不一定,因为你不知道在哪里会出现异常。
l 对方在用某功能,可是他要传什么是不确定的,那么a/b中b==0就有可能会发生。编写功能的人在功能上加上一个throws关键字的标识,说这个程序在运行的时候可能会出现问题
l 声明与不声明有什么不同?
声明了的话,再把异常抛给主函数的时候,主函数必须做出处理,不处理的编译不通过,不让你用。主函数要么将其抛出去,要么进行捕获,才能编译通过。声明的话,传对了就没有事了,传错了就出问题了,运行不过去。
逐级的往上给,传多层都无所为,最后是主函数调用再给虚拟机,到虚拟机这里到头了,虚拟机用默认的方式给解决掉。
l 在catch中的处理方式有很多,for循环,调用函数,内部类都没有问题。
l 例:去商店买面包,上面写着,已过三天,可能过期。降价处理,原来三块,现在三毛,你买了。你不吃,给别人吃(throws)。你打开袋子,一会没有长毛,你就把它给吃了(程序正常)。一看面包长毛了,放在微波炉里加热了一下,又给吃了(try-catch)。
5、多异常的处理
l 用throws Exception的方式声明异常其实不好,如果你知道抛出的异常是算术异常的话,声明的具体一些(声明为ArithmeticException),VM处理的话,会处理的更具体一些。这才是声明的一般的特点。声明多个具体呢,我就会处理多个具体。(如,声明多个异常:throwsArithmeticException,ArrayIndexOutOfException),声明了几个就要有几个针对性的处理(对应另外几个catch();)。函数当中一有异常发生,这个函数就已经结束了,不可能同时捕获到了多个异常。当如果只用一个catch捕获所有的异常的时候,用catch(Exceptione){},利用的多态性,但是它处理的没有针对性(try-catch的时候里面要写针对性的处理,要有与之对应的catch,看throws中有有几个catch)。
l 在捕获了有针对性的异常后,再写上catch(Exceptione){}好不好?
不好。第一,你都不知道会抛出什么异常,你抛出了之后,相当与把问题隐藏,而程序还在继续运行(出果出现了声明之外的异常,这时应该做的是把程序停掉,我们得知道,到底是在哪里卡住了,到底哪里出问题了,哪个功能是我们要进行修正的)。
l 对多异常的处理。
Ø 声明异常时,建议声明更为具体的异常。这样处理的可以更具体。
Ø 对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面(如果父类异常放在最上面的话,其他的catch都是多余的)。
l 建立在进行catch处理时,catch中一定要定义具体处理方式。
Ø 不要简单定义一句e.printStackTrace(),也不要简单的就书写一条输出语句。
Ø 真的发生问题了,我们是不打印的,我们会用一个硬盘文件给它记录下来,这个我们称之为异常日志文件,记录着我们程序每天的一些运行状况(几点几分出现了什么问题代码的维护人员经常看这些日志,进而解决一些bug)。
Ø 我们学习为了方便,我们打印一是看到代码的运行流程,二是能看到代码的运行结果。
6、自定义异常
l Java对特有的异常进行了封装,我们能不能对自己的项目中的对象也进行特有的封装呢?
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。所以对于这些特有的问题可以按照java的对问题封装的思想。将特有的问题,进行自定义的异常封装。
l 当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。要么在内部try catch处理。要么在函数上声明让调用者处理。主函数在调用一个声明异常的方法的话,主函数也有两个方式,要么try-catch要么抛。
l 用System.out.prinltn(“e.toString()”);发现打印的结果中只有异常的名称,却没有异常的信息。因为自定义的异常并未定义信息。
l 继承Exception原因:(当然也可以继承自Error)
异常体系有一个特点:因为异常类和异常对象都被抛出(因为他们会倒导致程序的跳转),他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。只有这个体系中的类和对象才可以被throws和throw操作。
l 自定义异常,需求:
在本程序中,对于除数是-1,也视为是错误的是无法进行运算的。
那么就需要对这个问题进行自定义的描述。
//要继承自Exception去这个体系中就有了异常的特性,有了异常中的那些方法。定义的目的就是为了生成对象。我们自定义的异常Java不认识,这时就要求我们手动的建立对象,并进行抛出。Java的异常可以手动抛出,也可以由Java自动的抛出。
class FuShuExceptionextends Exceptio//自定义异常:必须是自定义类继承Exception。
{
private int value;
FuShuException()
{
super();
}
/*
如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了。所以子类只要在构造时,将异常信息传递给父类通过super语句。那么就可以直接通过getMessage方法获取自定义的异常信息。
*/
FuShuException(String msg,int value)
{
super(msg);
this.value = value;
}
public int getValue() //获取负数异常的负数的值。
{
return value;
}
}
class Demo
{
int div(int a,int b)throws FuShuException
{
if(b<0)
throw newFuShuException("出现了除数是负数的情况------ / by fushu",b);//手动通过throw关键字抛出一个自定义异常对象。
return a/b;
}
}
小技巧:在编译的时候,但凡出现:“未报告的异常FuShuException;必须对其进行捕获或抛出”,这个错误的提示话,恭喜你,你已经进入到了语法错误的最后的环节了。
class ExceptionDemo3
{
public static void main(String[] args)
{
Demo d = new Demo();
try
{
int x = d.div(4,-9);
System.out.println("x="+x);
}
catch (FuShuException e)
{
System.out.println(e.toString());
System.out.println("错误的负数是:"+e.getValue());//e.getValue()这是自定义异常中所特有的方法
}
System.out.println("over");
}
}
/*
class Throwable //Throwable的子类Error中有一个构造方法Error(Stringmsg);
{
private String message;
Throwable(String message)
{
this.message = message;
}
public String getMessage()
{
return message;
}
}
class Exceptionextends Throwable //Exception继承自父类Throwable,当传入msg后,就要利用父类中的getMessage()方法获得字符串信息。
{
Exception(String message)
{
super(message);
}
}
*/
7、throw和throws的区别
l 位置不同:throws使用在函数上[写在“)”和“{”之间]。 throw使用在函数内。
l 跟班不同:throws后面跟的异常类(可以跟多个用逗号隔开)。throw后跟的是异常对象。
8、RuntimeException
l ArithmeticExceptionextends RuntimeException,算术异常有两个构造方法,一个是空参数的(ArithmeticException()),一个是带参数的(ArithmeticException(Strings),可自定义).
l int div(int a,int b)
{
if(b<0)
thrownew ArithmeticException(“被零除了”);
return a/b;
}
Ø throw new ArithmeticException(“被零除了”);这条语句为什么不声明,也能编译能过,而写成throw newException(“被零除了”);不能编译通过呢?
ArithmeticExceptionextends RuntimeException,只有这个异常的子类是非常特殊的RuntimException及它的子类,如果在函数内抛出了,函数上不用声明。
l int div(int a,int b)throws ArithmeticException
{
Return a/b; //主函数什么也没做,也没有问题。
}
Ø Exceptoin中有一个特殊的子类异常RuntimeException 运行时异常。如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过;
Ø 之所以不用在函数声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
l 对于异常分两种:
Ø 编译时被检测的异常。(在javac编译时期,如果方法中抛出了非runtime异常或者其子类,可是上面没用有throws标识,它就识为有安全隐患的。这些异常是可处理的,要标识出去让调用者处理。如果函数上标识了某些异常的话,调用者必须也要有对应的处理方式,要么抛,要么try。如果没有标识的话,若出现了异常对象,会判断一下是不是RuntimeException,如果是,你标不标识我都不管,程序停下来就好了)
Ø 编译时不被检测的异常(运行时异常。RuntimeException以及其子类)
l 自定义异常的另一个选择:自定义异常时,如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException。
l RuntimeException的一个子类NullPointException
固定值和空比没有问题,因为空没有调用方法。
不能throws抛,异常隐藏。我必须让你停掉,看看到底发生什么事情了。
l RuntimeException的一个子类IndexOutOfBoudsException角标越界。
如果访问到了不存在的角标程序一定要停掉,你要访问的元素都不存在你怎么拿角标去运算。这时候就有必要想下代码。
Ø 角标越界里还有两个小弟:ArrayIndexOutOfBoundsException,StringIndexOutOfBoundsException
l Object类中的一个方法,wait(longtimeout):要等待的最长的时间(ms为单位)。它在函数声明的时候声明了一个InterruputedException(异常发生,可以处理,不会完全影响运算,还可以执行),在抛出的时候却却抛出了三个。还有两个没有声明,IllegalArgumentException()和IllegalMonitorStateException,因为它们两个是RuntimeException的小弟(不需要去标识,你只要做了某件事情,我就让程序停下来,因为影响了运算,必须先修正了代码后,再让你运行)
9、异常练习
/*
毕老师用电脑上课。开始思考上课中出现的问题。
比如问题是:1.电脑蓝屏 2.电脑冒烟。
要对问题进行描述,封装成对象。可是当冒烟发生后,出现讲课进度无法继续。出现了讲师的问题:课时计划无法完成。
*/
classLanPingException extends Exception
{
LanPingException(String message)
{
super(message);
}
}
classMaoYanException extends Exception
{
MaoYanException(String message)
{
super(message);
}
}
classNoPlanException extends Exception
{
NoPlanException(String msg)
{
super(msg);
}
}
class Computer
{
private int state = 3; //设置一具特殊的状态位,表示电脑的状态,很好
public void run()throwsLanPingException,MaoYanException
{
if(state==2)
throw newLanPingException("蓝屏了");
if(state==3)
throw newMaoYanException("冒烟了");
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();
}
public void prelect()throwsNoPlanException
{
try
{
cmpt.run();
}
catch (LanPingException e)
{
cmpt.reset();
}
catch (MaoYanException e) //不能把e抛给张老师,张老师不是电脑维修师,他处理不了。要将冒烟异常转换成我的异常[讲课不能继续],再把它抛给张老师,能被处理。
{
test(); //这句话要先写,若把下面的写在前面的话,test()执行不到。
throw newNoPlanException("课时无法继续"+e.getMessage());
//throw单独存在的时候页面千万不要写语句因为它就是函数的结束标识了,除了它之外,还有return。
}
System.out.println("讲课");
}
public void test()
{
System.out.println("练习");
}
}
classExceptionTest
{
public static void main(String[] args)
{
Teacher t = new Teacher("毕老师");
try
{
t.prelect();
}
catch (NoPlanException e)
{
System.out.println(e.toString());
System.out.println("换老师或者放假");
}
}
}
10、异常-finally
l finally代码块:定义一定执行的代码,通常用于关闭资源。(其他功能,某些代码一定要执行一下,可以往这里面放)
l 调用方法的时候要看方法是否抛出了了异常,如果抛出了异常,你可以处理的话,要写try-catch。
l 连接数据库,不断开的话,一:你占着服务器的资源,二:你占着服务器的连接。为了让大家都能连接上数据库,在访问数据库后要断开。无论是否在数据库中取到要访问的数据,最后的断开一定要执行。
public voidmethod()throws NoException
{
try
{
连接数据库;
数据操作;//throw new SQLException();数据库异常
}
catch (SQLException e)
{//数据库异常发生后,这里面可以有特定的数据库异常处理方式(不抛出去,你把我给你的数据往数据库里放,发生了异常,你把数据库异常抛给我。这不合适,我只是拿数据而已,往哪里去存,我不知道,这是你的事。你暴露了你那个程序的封装性)。负责处理数据库层的哥们最清楚要怎么做。
数据库异常捕获到后,可以做什么样的动作?可以做两种动作:
(1)会对数据库进行异常处理;
(2)throw newNoException();
//把问题暴露出去,但不暴露本层的问题,只暴露一个对方能够识别的问题就可以了。这叫做问题的封装(有些问题是要内部处理的,处理完成后,告诉对方结果就可以了)。(2)不可以省。人家要货呢,你把漏水的地方给解决了,可以销售员什么都不知道,而且还没有拿到货。这里有关联性,你没有把关联性的问题给提供出去。
例:销售员告诉仓库管理员说,我要一批货,可以仓库漏水了,货长毛了。仓库管理员要做的就是把漏水的地方修好,之后对销售说,说货没了。
}
finally
{
关闭数据库; //该动作,无论数据操作是否成功,一定要关闭资源。
}
}
l 上机面试的时候,如果涉及到异常的问题,没有做finally的问题,没有做异常的处理,没有进行资源的关闭,程序是有问题,面试官会认为你没有编程经验。
l JVM可以创建文件,它调的是windows或Linux底层的资源,无论资源有不有创建成功,都要将资源给释放了。
------- android培训、java培训、期待与您交流! ----------