异常 顾名思义 就是不正常 的意思
在Java中,异常有两种:Error和exception ,他们的根类都是Throwable
ps:异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象
1. 严重的错误 Error,表示该错误 无法通过处理的修改好
2. 异常 Exception ,表示该异常可以通过修改编写的代码完善好。异常分成两类:编译时异常 和 运行时异常
2.1 编译时异常,编译时无法编译通过。如日期格式化异常
2.2 运行时异常(Exception的子类),运行时可能会报错,可以不处理。如数组越界异常
编译异常:
抛出的是编译异常, 必须处理, 不处理编译失败
运行异常:
方法中抛出的异常,都是RuntimeException或者是他的子类异常
抛出的是运行时期异常,无需在方法上写throws
不能处理,如果出现只能直接修改代码
3. 异常的处理有两种方式:
3.1 抛出异常: 方法声明上加 throws 异常类名
3.2 捕获异常 :
try{
需要检测的异常;
} catch(异常对象) {
异常处理代码
异常对象.printStackTrace打印异常信息
}
4. 异常的处理流程:
比方说Java的异常处理流程就是,
1. 因为发生异常,产生异常对象(对象中包含异常名称、异常内容、异常产生的位置)
2. 抛到 异常调用者处,如果异常调用者不处理,则一直抛,抛到main()处,如果main()也不处理最终抛到 JVM,在控制台上显示,同时程序终止
throw用在方法内,用来抛出一个异常对象,将这个异常对象抛到调用者处,并结束当前方法的执行。(throws用在方法 名旁)
trow格式:throw new 异常类名(参数);
throws的格式:修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2… { }
通过throws进行声明,让调用者去处理。若该方法可能有多种异常情况产生,那么在throws后面可以写多 个异常类,用逗号隔开
使用异常需注意:
1. 如果父类抛出了多个异常,子类覆盖父类方法时,只能抛出相同的异常或者是他的子集(访问范围)
2. 父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
3. 当多异常处理时,捕获处理,前边的类不能是后边类的父类
try{
异常代码;//产生异常,直接捕获处理
}catch(AAAException e){
//处理方式
}catch(BBBException e){
//处理方式
}catch(CCCException e){
//处理方式
}
AAA Exception是BBB Exception的子类;子类异常要在上面的catch处理,父类异常在下面的
catch处理
4. 在try/catch后可以追加 finally 代码块,其中的代码一定会被执行,通常用于资源回收。
public static void main(String[] args) {
int i=getNumber();
System.out.println(i);
}
public static int getNumber(){
int i=1;
try {
return i;
} catch (Exception e) {
return i;
}finally{
System.out.println("======");
++i;
}
}
说明:首先调用debug模式,可以看到程序走到了try中return i
,接着走到了finally语句块中,执行了输出语句, ++i , 而且
debug的变量显示区,显示i 为2,最后执行到main方法,
i 再次显示为1 ,并且打印的也是1.说明是先执行return,
但是return没有执行完毕(你可以认为是把i 的值放到了
盒子中,就是你在盒子外面怎么操作,最终取出盒子中的值,
还是不变的),接着执行finally,finally执行完毕,最后return才返回结果
自定义的异常
有时候系统的自带的异常不能满足我们的业务需求,这时候就需要我们 自定义异常了
java中所有的异常类,都是继承Throwable,或者继承Throwable的子类,该异常才可以被throw抛出。所以我们自定义异常需要继承Throwable的子类。格式如下:
Class 异常名 extends Exception{ //或继承RuntimeException都行
public 异常名(){ //为什么要定义构造函数,因为Java中的异常描述类中有提供对异常对象的初始化方法
}
public 异常名(String s){
super(s); //如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可。
}
}
继承有两种选择 :1. 继承exception 2.继承RuntimeException 。到底选择继承什么呢?
1.继承Exception,必须要throws声明,一声明就告知调用者进行捕获,一旦问题处理了调用者的程序会继续执行。
2.继承RuntimeExcpetion,不需要throws声明的,这时调用是不需要编写捕获代码的,因为调用根本就不知道有问题。一旦发生异常,调用者程序会停掉,并有jvm将信息显示到屏幕,让调用者看到问题,修改代码。
// 第一种情况(继承exception)的例子
//自定义异常类
class NoAgeException extends Exception{
NoAgeException() {
super();
}
NoAgeException(String message) {
super(message);
}
}
//Person类
class Person{
private String name;
private int age;
Person(String name,int age) throws NoAgeException {
//加入逻辑判断。
if(age<0 || age>200) {
throw new NoAgeException(age+",年龄数值非法");
}
this.name = name;
this.age = age;
}
//定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
public String toString() {
return "Person[name="+name+",age="+age+"]";
}
}
//测试类
class ExceptionDemo{
public static void main(String[] args) {
try {
Person p = new Person("xiaoming",20);
System.out.println(p);
}
catch (NoAgeException ex){
System.out.println("年龄异常啦");
}
System.out.println("over");
}
}
PS:其实平台写代码时报错,是经过两个步骤的(一个是创建异常对象,第二步抛出异常或处理),只不过是Java的开发人员封装好的
PS2:异常处理,指处理的一种可能性,即有了异常处理的代码,不一定会产生异常。如果没有产生异常,则代码正常执行,如果产生了异常,则中断当前执行代码,执行异常处理代码