异常:
是什么?是对问题的描述,见问题进行对象的封装
异常机制可以使程序中的异常处理代码和正常业务分离,保证程序代码更加优雅,并可以提高程序的健壮性。
程序在运行时发生错误是不可避免的
在进行错误处理时,发现错误根据具体的情况可以划分为两大类
1.致命错误
不可恢复,例如内存泄露
2.非致命错误
读取一个文件,文件不存在
修改一个文件夹的名字,但是文件夹目前被使用
1.对于无法处理的错误,基于面向对象的思想,Java语言对其进行封装,成为一个对象,名字叫做Error,即不可恢复的错误
2.对于某些非致命性的错误,可以通过某种形式进行处理,Java语言对其进行封装,称为一个对象,名字叫做Exception,即可处理的异常现象
异常体系:
Throwable
Error
Exception
RuntimeException
异常体系的特点:1.异常体系中的所有类以及建立的对象都具备可抛性
2.也就是说可以被throws和throw关键字所操作
3.只有异常体系具备这个特点
Java的异常被分为两类:Checked ( 编译时异常 ) 异常和 Runtime异常(运行时异常),所有的RuntimeException类及其子类的实例被称为Runtime异常;不是RuntimeException类及其子类的异常实例则被称为Checked异常。
Checked异常体现了java的设计哲学———没有完善错误处理的代码根本就不会被执行
对于Checked异常的处理方式有两种:
1.当前方法明确知道如何处理该异常,程序应该使用try...catch块来捕获该异常,然后在对应的catch块中修复该异常。
2.当前方法不知道如何处理该这种异常,应该在定义方法声明时抛出该异常。
Runtime异常则更加灵活,Runtime异常无需显式声明抛出,如果程序需要捕获Runtime异常,也可以用try...catch块来实现。
1.异常体系的分类非常庞大
2.常见的异常
NullPointException
IOException
SQLException
如果函数声明了异常,调用者需要进行处理,处理方式:
可以throws 可try。
1,编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。
这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。
这样的问题都可以针对性的处理。
2,编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。
这种问题的发生,无法让功能继续,运算无法进行,更多是因为调用者的原因导致的而或者引发 了内部状态的改变导致的。
那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者 对代码进行修正。
try…catch…finally(TCF结构)
语法结构:
try{
可能引发异常的语句//业务实现代码
}catch(可能出现的异常现象){
针对异常现象的处理语句
}finally{
(清理现场)
}
如果执行try块里的业务逻辑代码时出现异常,系统会自动生成一个异常对象,该异常对象被提交给Java运行环境,这个过程被称为———抛出(throws)异常。
当java运行环境收到异常对象时,会寻找处理该异常对象的cathch块,如果找到合适的catch块,则把该异常对象交给该catch处理,这个过程被称为———捕获(catch)异常;如果java运行环境找不到捕获异常的代码块,则运行时环境终止,java程序也将退出。
注意:进行异常捕获时,一定要记住要先捕获小异常,再捕获大异常。
注try块与if语句不一样,try块后的花括号({....})不可以省略,即使try块里只有一行代码,也不能省略这个花括号,与之类似的是,catch后的花括号也不能省略,还有一点需要指出:try块里声明的变量时代码块内局部变量,它只在try块内有效,在catch块内不能访问。
try语句块用于包裹可能引发异常的语句
try语句块中的语句不是一定会引发异常现象的
try语句块中的语句一旦引发异常,程序执行流程将自动跳转到对应的处理代码中,则从引发异常的语句向后直到try语句块结束大括号处的代码将不再运行
catch语句块定义了针对try语句块中所引发的异常进行分门别类的处理
一个try语句块可以携带一个或多个catch语句块,但是只能引发其中任意一个处理方案,不可能执行一种以上的处理方法
catch语句块超过一个时,需要对其层次进行自上而下由小到大的层级排列,相互之间没有层级关系的语句可以随意排列顺序,不做要求
注catch是用于处理异常,如果没有catch就代表异常没有被
处理过,如果该异常是检测时异常,那么就必须声明。
fianlly代码块:定义一定执行的代码,通常用于关闭资源
finally语句块定义了一段总是被运行的代码,无论try语句块中是否出现异常现象
finally语句块通常用于做现场清理的工作,例如try语句块中打开了一个文件,但是由于运行过程中出现了异常,转入到catch执行处理代码后,文件并没有被正常关闭,此时需要利用finally语句块来进行处理,将文件正常关闭
注Java的垃圾回收机制不会回收任何物理资源,垃圾回收机制只能回收对内存中对象所占用的内存。
注不要在finally块中使用如return或throw等导致方法终止的语句,一旦在finally块中使用了return或throw语句,将会导致try块,catch块中的return,throw语句失效。
注1.finally中定义的通常是关闭资源代码,因为资源必须释放。
2.finally只有一种情况不会执行,当执行到System.exit(0):系统推出,finally不会执行。
异常处理器中的catch与finally可以共存,一个try语句可以携带一到多个catch语句块,但是只能携带一个finally语句块
异常处理器可以选择只携带catch语句块或finally语句块
异常处理流程代码也可以放在任何可能放可执行性代码的地方,因此完整的异常处理流程既可以放在try块里,也可以放在catch块,finally块里。
catch语句块中针对出现的异常现象根据Java面向对象的原则,将出现的问题包装成一个对象,该对象中包含了异常现象对应的所有信息
异常对象名称
引发异常的原因
异常出现的位置(错误堆栈)
catch语句块中针对出现的异常现象根据Java面向对象的原则,将出现的问题包装成一个对象,该对象中包含了异常现象对应的所有信息
1.异常对象名称
toString()
2.引发异常的原因
getMessage()
3.异常出现的位置(错误堆栈)
printStackTrace()
4.返回该异常的跟踪栈信息
getStackTrsce()
自定义异常即扩展Exception类,创建异常类对象
用户自定义异常都应该继承Exception基类,如果希望自定义Runtime异常,则应该继承RuntimeException基类。定义异常时通常需要提供两个构造器:一个是无参数的构造器;另一个是带一个字符串参数的构造器,这个字符串将作为该异常对象的描述信息(也就是异常对象的getMessage()方法的返回值)。
下面穿件了一个自定义异常类:
public class AuctionException extends Exception
{
//无参数的构造器
public AuctionException(){}
//带一个字符串参数的构造器
public AuctionException(String msg)
{
super(msg);
}
}
自定义异常:按照java的面向对象思想,将程序中出现的特有问题进行封装。
1.针对某种异常现象可以指定抛出何种异常,在抛出异常时,使用throw指令抛出具体的异常对象
throw 异常对象
2.抛出异常对象后,JVM将检测抛出的异常是否被处理,此时可以通过下列两种形式来进行处理
对抛出的异常进行捕获
对抛出的异常不进行捕获,继续向上层调用者抛出
使用throws声明抛出异常的思路是:当前方法不知道如何处理这种类型的异常,该异常该有上一级调用者处理;如果main方法也不知道该如何处理这种类型的异常,也可以使用throws抛出异常,该异常将交给JVM处理。JVM对异常的处理方法是:打印异常的跟踪栈信息,并终止程序运行,这就是前面程序在遇到异常后自动结束的原因。
Throws声明抛出只能在方法签名中使用,throws可以声明抛出多个异常类,多个异常类之间可以逗号隔开。Throws声明抛出的语法格式如下:
throws ExceptionClass1,ExceptionClass2...
一旦使用了throws声明抛出该异常,程序就无须使用try...catch块来捕捉异常了。也就是说,调用该方法时,要么放在try块中显式捕获该异常,要么放在另一个带throws声明抛出的方法中,
public class ThrowsTest
{
public static void main(String[] args) throws Exception
{
//因为test()方法声明抛出IOException异常
//所以调用该方法的代码块要么处于try...catch中,
//要么处于另一个带throws声明抛出异常的方法中
test();
}
public static void test()throws IOException
{
//因为FileInputStresm的构造器声明抛出IOException异常
//所以调用FileInputStream的代码要么处于try...catch块中
//要么处于另一个带throws声明抛出的方法中
FileInputStream fis = new FileInputStream("a.txt");
}
}
Check异常的优势:——Check异常能在编译时提醒程序员代码可能存在的问题,提醒程序员必须处理该异常,或者声明该异常由该方法调用者来处理,从而可以避免程序员因为粗心而忘记处理该异常的错误。
当程序出现错误时,系统会自行抛出异常;除此之外,Java也允许程序自行抛出异常,自行抛出异常使用throw语句来完成。
如果需要在程序中自行抛出异常,则应使用throws语句,throw语句可以单独使用,throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例,语法格式如下:
throw ExceptionInstance
如果throw语句抛出的异常是Checked异常,则该throw语句要么处于try块里,显式捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给该方法的调用者来处理;
如果throw抛出的是Runtime异常,则该语句无须放在try块里,也无须放在带throws声明抛出的方法中,程序既可以显式使用try..catch来捕获并处理该异常,也可以完全不理会该异常,把该异常交给该方法调用者来处理。
throw定义在函数内,用于抛出异常对象
throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开
当函数内有throw抛出异常对象,并未进行try处理,必须在函数上声明,
否则都将编译失败。
注意:RuntimeException除外,也就是说,函数内如果抛出的是RuntimeException
异常,函数上可以不用声明。
1.方法抛出异常是对方法的定义进行声明,明确方法执行过程中可能引发异常现象,提醒调用者要对其进行处理
2.方法抛出异常要求调用者强制处理,除非抛出的异常为RuntimeException的子类,否则必须对其进行处理。可以利用此特点,设计自定义异常类的对象
1.异常现象在编程过程中及其常见,在开发过程中,如果调用了可能引发异常的语句,最常见的处理方案是针对对应的语句使用tcf结构对其进行处理,并打印错误的异常堆栈信息,然后针对错误信息进行分析,制作对应的异常处理方案
2.在开发调试期间,打印的异常信息可以作为编程人员的参考性信息,但是在实际运行期间,此类信息必须要屏蔽掉,以更友好的形式展示给最终用户
1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2.如果父类方法抛出多个异常,子类在覆盖该方法时,子类只能抛出父类异常的子集
3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常,如果子类方法发生了异常,就必须进行try处理,绝对不能抛。
*/
Exception
|--AException
|--BException
|--CExcepton
*/
//定义了3个异常类
class AException extends Exception{
}
class BException extends AException{
}
class CException extends AException{
}
//父类抛出A异常
class Fu{
void show() throws AException{
}
}
class Test{
void function(){
try{
f.show();
}catch (AException e){
}
}
}
//子类只能抛出A异常或者B异常
class Zi extends Fu{
void show() throws BException{
}
}
1.处理方式有两种:try或者 throws
2.调用到抛出异常的功能时,抛出几个,就处理几个
一个try对应对个catch
3.多个catch,父类的catch放到最下面
4.catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace,
输出语句,也不要不写。
当捕获到的异常,本功能处理不了时,可以继续再catch中抛出,
try{
throw new AExcepton();
}catch(AException e){
throw e;
}
如果该异常处理不了时,但并不属于该功能出现的异常,
可以将异常转换周,在抛出和该功能相关的异常。
或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,
让调用者知道,并处理。也可以将捕获异常处理后,转换新的异常。
try{
throw new BException();
}catch(AException e){
//对AException处理
throw new BException();
}
异常的注意事项:
在子父类覆盖时;
1.子类抛出的异常必须是父类异常的子类或者子集
2.如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛
针对finally语句块的执行特点,如果在finally语句块中添加了return语句,则执行到此处时,会对整体方法的返回值进行修改。