1.异常的定义及分类
1.异常的简单定义:程序在编译过程或运行时出现的不正常行为
2.异常分类:Java中的异常可分为Error(错误)和Exception(异常)两类。前者程序本身无法处理(一般涉及jvm方面),而后者程序可通过一定的方式进行处理。
第一类异常 | 第二类异常 |
---|---|
编译时被检测的异常 | 编译时不被检测的异常(运行时异常,RuntimeException以及其子类) |
以下为java异常体系继承关系,Error与Exception的父类为Throwable(可抛出)
3.异常类常用方法:
String getMessage()
返回此对象的详细消息字符串。
[异常信息]void printStackTrace()
将此对象及其追踪输出至标准错误流。
[异常名称:异常信息,异常出现的位置,堆栈跟踪信息]
tips:jvm中的默认异常处理机制String toString()
返回此对象的简短描述。
[异常名称:异常信息]
tips:java为了增强代码阅读性会将父类名作为子类后缀名(借鉴)
4.使用异常的好处
将程序运行中的问题进行封装 | 将正常流程代码与问题处理代码进行分离,增强代码可读性 |
---|
2.常见异常
异常名称 | 说明 |
---|---|
java.lang.ArrayIndexOutOfBoundsException | 数组索引越界异常 |
java.lang.ArithmeticException | 算术条件异常 |
java.lang.NullPointerException | 空指针异常 |
java.lang.ClassNotFoundException | 找不到类异常 |
java.lang.NegativeArraySizeException | 数组长度为负异常 |
java.lang.ArrayStoreException | 数组中包含不兼容的值抛出的异常 |
java.lang.IllegalArgumentException | 非法参数异常 |
IOException | 操作输入流和输出流时可能出现的异常 |
EOFException | 文件已结束异常 |
FileNotFoundException | 文件未找到异常 |
3.异常的处理
常用格式一[捕捉+处理+关闭资源]:
try{
//待检测的代码
}catch(异常类 变量名){
}finally{
//一定会执行的操作
}
常用格式二[捕捉+处理]:
try{
//待检测的代码
}catch(异常类 变量名){
}
常用格式三[捕捉+关闭资源]:
try{
//待检测的代码
}finally{
// 一定会执行的操作
}
注意1:在try catch语句中的代码块自成一块变量作用域
注意2:finally中的语句一般用于关闭资源或一些必须执行的操作
注意3:finally中的语句即使在return
后依旧会执行,除非程序执行System.exit(0)
[jvm结束]
执行过程: try
–>catch()
(父类的引用接收子类对象)–>finally
注意: try代码块中一旦发生异常,异常语句后面的代码就停止执行
4.异常声明
格式: 方法名() throws Exception
说明:在方法上声明异常,便于提高安全性,让调用者进行处理,不处理则编译失败
处理过程:遇到异常
–>捕捉或抛出
(极端情况:抛出异常给jvm虚拟机)
5.多异常处理
1.声明异常时建议声明更具体的异常,这样在处理更加具有针对性
2.处理时可以添加多个catch
语句对相应具体异常进行处理
3.如果多个catch
块中的异常出现继承关系,则父类异常块应该放在后面(catch
顺序执行)
4.建议在catch
中对异常进行具体的处理,而不要仅仅进行简单的异常说明
处理方式举例:[将异常以文件形式记录下来(异常日志文件)]
简单举例:
try {
int end=eo.getEnd(-1,0);
} catch (SpecialException e) {
System.out.println("错误的首位数为:"+e.getNum());
}catch(ArithmeticException e2){
System.out.println(e2,toString());
}
6.自定义异常
应用场景:对具体项目中的特有问题进行自定义异常封装(参照java的异常封装思想)
//演示自定义异常
class SpecialException extends Exception{
int numExc;//特殊异常数据
public SpecialException(String msg){
super(msg);//调用父类构造方法
}
public SpecialException(String msg,int numExc){
super(msg);//调用父类构造方法
this.numExc=numExc;
}
public int getNum(){
return numExc;
}
}
//测试用类
class ExceptionOwn{
public int getEnd(int a,int b) throws SpecialException{
if(a>5)
throw new SpecialException("希望您的首位数字不要超过5");//抛出自定义异常信息的自定义异常
if(a<0)
throw new SpecialException("首位数字不能小于0",a);//抛出自定义异常信息的自定义异常
if(b==0)
throw new ArithmeticException("注意第二位参数不能为0");//抛出自定义异常信息的系统异常
return a/b;
}
}
1.建议自定义异常类以exception结尾[后缀名] extends Exception
2.自定义异常只能在代码中手动抛出([例:通过条件判断语句在特殊情况下使用throw关键字手动抛出])
3.若在方法中通过throw抛出自定义异常,必须进行以下两种处理方式:
在方法内部进行try catch 处理[自己处理];在方法上进行声明让该方法的调用者进行处理
4.一般情况下,方法内出现异常,方法上需要使用throws
关键字进行声明
特殊:runtimeException
在方法中出现throw
关键字,方法上可以不用throws
声明,如果在方法上抛出该异常,调用者可以不用对该异常进行try catch
处理
在该类情况下程序的设计者希望程序停止运行(因为这是由于调用者的错误使用造成的,程序无法继续运行;此时程序设计者希望使用者重新编写代码)
[例] NullPointerException ArithmeticException IndexOutOfBoundsException
自定义异常处理思想:如果该异常出现后,程序无法继续运行。则可以令该异常继承RuntimeException
定义自定义异常的异常信息: 在自定义异常类构造方法中直接调用super(msg)
即可
还可以对异常信息进行特色化处理(例如输出运行中的输入数据)[通过定义多参数的构造函数以及相应的变量,并定义相应的getter方法]
throws和throw的区别:
throws使用在方法上;throw使用在方法内
throws后面跟异常类,可以跟多个,用逗号隔开;throw后者后跟异常对象
自定义系统异常的异常信息:在方法中通过throw new 系统异常(msg)
public int getEnd(int a,int b) throws SpecialException{
if(b==0)
throw new ArithmeticException("注意第二位参数不能为0");//抛出自定义异常信息的系统异常
return a/b;
}
7.异常在子类父类覆盖中的使用特点
1.子类继承父类,并对父类中有异常抛出的方法进行覆盖。则该方法在子类中只能抛出父类中的异常或其子类异常,不能抛出新的异常。
2.如果父类中的方法抛出多个异常,则子类在覆盖该方法时只能抛出父类中异常的子集。
3.如果父类或接口中的方法无异常抛出,则子类覆盖该方法时也不能抛出异常。如果出现异常,则只能在方法内部用try
进行处理。
8.一个完整的简单异常应用实例
场景描述:司机驾驶汽车,汽车类可能会抛出两个异常,随其状态值而改变。针对汽车具体的异常,司机类也可能会抛出特殊异常。其中有对各异常的简单处理。
package com.dream.home_1102.exception;
//定义货车发动机过热异常
class CarHotException extends Exception{
public CarHotException(String msg){
super(msg);
}
}
//定义货车发动机损毁异常
class CarDestroyException extends Exception{
public CarDestroyException(String msg){
super(msg);
}
}
//定义司机无法继续驾驶异常
class DriverStopException extends Exception{
public DriverStopException(String msg){
super(msg);
}
}
//定义汽车类
class Car{
private int state=3;//汽车是否正常运行的状态码
public Car(int s){
state=s;
}
//定义汽车行驶方法
public void run() throws CarHotException,CarDestroyException{
if(state==2)
throw new CarHotException("发动机过热");
if(state==3)
throw new CarDestroyException("发动机已经损坏");
System.out.println("汽车正在行驶");
}
//定义汽车停止冷却方法
public void restCold(){
state=1;
System.out.println("经过修整,汽车的发动机温度回归正常");
}
}
//定义司机类
class Driver{
private String name;
public Driver(String name){
this.name=name;
}
public void drive(Car c) throws DriverStopException{
try {
c.run();
} catch (CarHotException e) {
System.out.println(e.toString());
c.restCold();
} catch (CarDestroyException e) {
throw new DriverStopException("司机停止行驶"+e.getMessage());
}
}
}
public class ManagerException {
public static void main(String[] args) {
Driver k=new Driver("K先生");
Car car1=new Car(1);
Car car2=new Car(2);
Car car3=new Car(3);
try {
k.drive(car1);
k.drive(car2);
k.drive(car3);
} catch (DriverStopException e) {
System.out.println(e.toString());
System.out.println("K先生可以考虑换一辆车了");
}
}
}
运行结果:
汽车正在行驶
com.dream.home_1102.exception.CarHotException: 发动机过热
经过修整,汽车的发动机温度回归正常
com.dream.home_1102.exception.DriverStopException: 司机停止行驶发动机已经损坏
K先生可以考虑换一辆车了