Java基础知识点(七)
Java异常
一、概念
1、异常:有异于常态,和正常情况不一样,有错误出现,阻止当前方法或作用域。
2、异常处理:将出现的异常提示给编程人员与用户,使原本将要中断的程序继续运行或者退出。并且能够保存数据和释放资源。
二、异常体系结构
-
1、所有异常都继承于Throwable类,其下有两大子类:
- (1)Error类:错误,一般编程人员不太接触,如虚拟机错误、线程死锁。硬伤:使程序崩溃
- (2)Exception类:异常,编码、环境、用户输入等问题,其子类主要有:
-
非检查异常(运行时异常RuntimeException):【由java虚拟机自动捕获】如空指针NullPointer、越界ArrayIndexOutofBounds、错误类型转换ClassCast、算数异常Arithmetic等
-
- 检查异常CheckException:【需要手动添加捕获和处理语句】文件异常IO等
三、异常处理:
try-catch(多catch块)-finally
- (1)try块:负责捕获异常,一旦try中发现异常,程序的控制权将被移交给catch块中的异常处理程序。【try语句块不可以独立存在,必须与 catch 或者 finally 块同存】
- (2)catch块:如何处理?比如发出警告:提示、检查配置、网络连接,记录错误等。执行完catch块之后程序跳出catch块,继续执行后面的代码。
-
编写catch块的注意事项:多个catch块处理的异常类,要按照先catch子类后catch父类的处理方式,因为会【就近处理】异常(由上自下)。
-
编写catch块的注意事项:多个catch块处理的异常类,要按照先catch子类后catch父类的处理方式,因为会【就近处理】异常(由上自下)。
- (3)finally:最终执行的代码,用于关闭和释放资源等
try{
//一些会抛出的异常
}catch(Exception e){
//处理该异常的代码块
}finally{
//最终要执行的代码
}
try-catch-finally执行顺序:
- ①执行try{}块
- ②如果try{}块有异常产生,执行catch{}块
- ③无论有没有异常都要执行finally{}块,这里可以看出只要finally中有return,必然返回finally{}中的return
return的执行,
- ①,如果finally{}块中有return语句,只执行finally{}块中的return语句
- ②,如果finally{}块中没有return语句,如果try{}有异常,则返回catch{}中的return语句,不然执行try{}中return语句
如果finally语句块中有return语句,try/catch语句块中的return语句会被忽视
在try-catch-finally之外还可以有return,这种情况下在catch和try里面两者之一能有return,不能同时有,且当当有两者之一语句执行时会返回两者之一的return,不会返回语句外的return值,当两者之一的return不执行时才会返回语句外的return值。finally与语句外不能同时存在return,当否则会报错
四、Java 中的异常抛出以及自定义异常
两个重要的关键字:throw和throws
- 1.throws的异常列表可以是抛出一条异常,也可以是抛出多条异常,每个类型的异常中间用逗号隔开
- 2.方法体中调用会抛出异常的方法或者是先抛出一个异常:用throw new Exception()
throw写在方法体里,表示“抛出异常”这个动作 - 3.如果某个方法调用了抛出异常的方法,那么必须添加try catch语句去尝试捕获这种异常,
或者添加声明,将异常抛出给更上一层的调用者进行处理 - 4.自定义异常:
class 自定义异常类 extends 异常类型{
}
上面的异常类型可以是Exception,也可以是其子类
Java 中的异常链
只有Error,Exception,RuntimeException提供了带cause参数的构造器,其他的所有异常类只能通过initCause()来设置cause。
所有Throwable的子类构造器中都可以接受一个cause对象作为参数。cause是异常原由,代表着原始异常。既可以在当前位置创建并抛出行的异常,也可以通过cause追踪到异常最初发生的位置。
异常链是一种面向对象编程技术,指将捕获的异常包装进一个新的异常中并重新抛出的异常处理方式。原异常被保存为新异常的一个属性(比如cause)。这个想法是指一个方法应该抛出定义在相同的抽象层次上的异常,但不会丢弃更低层次的信息。
把捕获的异常包装成新的异常,在新异常里添加原始的异常,并将新异常抛出,它们就像是链式反应一样,一个导致(cause)另一个
这个想法是指一个方法应该抛出定义在相同的抽象层次上的异常,(将所有捕获到的异常包装为新的异常类,即定义在相同的抽象层次上抛出)但不会丢弃更低层次的信息。
实现异常链功能的两种基本写法:
public class ChainTest {
/**
* test1()抛出喝大了异常
* test2()调用test1()捕获喝大了异常,并且包装成运行时异常,继续抛出
* main方法中调用test2(),尝试捕获 test2()方法抛出的异常
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ChainTest ct = new ChainTest();
try{
ct.test2();
}catch(Exception e){
e.printStackTrace();
}
}
public void test1() throws DrunkException{
throw new DrunkException("喝酒别开车");
}
public void test2(){
try {
test1();
} catch (DrunkException e) {
// TODO Auto-generated catch block
RuntimeException newExc = new RuntimeException("司机一滴酒,亲人两行泪");
newExc.initCause(e);
throw newExc;
}
}
}