异常机制
基本概念
- 异常就是不正常,在Java中指程序执行中发生的不正常情况
- java.lang.Throwable类是Java语言中错误(Error)和异常(Exception)的超类
- 其中Error类主要用于描述Java虚拟机无法解决的严重错误,通常无法编码解决,如:JVM挂掉
- 其中Exception类主要用于描述因编程错误或偶然外在因素导致的轻微错误,通常可以编码解决
异常的分类
- java.lang.Exception类是所有异常的超类,分为如下
- RuntimeException - 运行时异常(非检测性异常)
- IOException和其它异常 - 其它异常(检测性异常)
所谓检测性异常就是指在编译阶段都能被编译器检测出来的异常
- RuntimeException类的主要子类
- ArithmeticException类 - 算术异常
- ArrayIndexOutOfBoundsException类 - 数组下标越界异常
- NullPointerException - 空指针异常
- ClassCastException - 类型转换异常
- NumberFormatException - 数字格式异常
- 五类异常的示例代码如下:
import java.io.IOException;
public class ExceptionTest {
/**
* 算数异常
* ArithmeticException
*/
public static void arithmeticException() {
int ia = 5;
int ib = 0;
System.out.println(ia/ib);
}
/**
* 空指针异常
* NullPointerException
*/
public static void nullPointerException() {
String ss = null;
System.out.println(ss.length());
}
/**
* 数组越界异常
* arrayIndexOutOfBoundsException
*/
public static void arrayIndexOutOfBoundsException() {
int[] xx = new int[5];
System.out.println(xx[6]);
}
/**
* 数字格式异常
* NumberFormatException
*/
public static void numberFormatException() {
String ss = "aaaa";
Integer bb = Integer.parseInt(ss);
System.out.println(bb);
}
/**
* 类型转换异常
* ClassCastException
*/
public static void classCastException() {
Exception ex = new Exception();
IOException io = (IOException) ex;
}
public static void main(String[] args) {
// ExceptionTest.arithmeticException();
// ExceptionTest.nullPointerException();
// ExceptionTest.arrayIndexOutOfBoundsException();
// ExceptionTest.numberFormatException();
// ExceptionTest.classCastException();
}
}
当程序执行过程中发生异常但又没有手动处理时,则由Java虚拟机采用默认方式处理异常,而默认处理方式就是:打印异常的名称、异常发生的原因、异常发生的位置以及终止程序
异常的避免
- 尽量使用if条件判断来避免异常的发生
- 过多的if条件判断会导致程序的代码加长、臃肿,可读性差(引出如下的异常解决办法)
异常的捕获
- 语法格式
try {
编写可能发生异常的代码;
}catch(异常类型 引用变量名) {
编写针对该类异常的处理代码;
}
...(可以写多条catch语句)
finally {
编写无论是否发生异常都要执行的代码;
}
- 注意事项
- 当需要编写多个catch分支时,切记小类型应该放在大类型的前面
- 可以用
catch(Exception e)
直接代替所有异常的抛出,因为Exception是异常的超类
异常的抛出
- 基本概念:
在某些特殊情况下有些异常不能处理或者不便于处理时,就可以将该异常转移给该方法的调用者,这种方法就叫异常的抛出。当方法执行时出现异常,则底层生成一个异常类对象抛出,此时异常代码后续的代码就不再执行。 - 语法格式:
访问权限 返回值类型 方法名称(形参列表) throws 异常类型1,异常类型2,…{ 方法体; }
如:public void show() throws IOException{}
- 子类方法重写原则:(父类抛出异常,子类继承父类方法)
- .要求方法名相同、参数列表相同以及返回值类型相同
- 要求方法的访问权限不能变小,可以相同或者变大
- 要求方法不能抛出更大的异常
- 子类重写的方法不能抛出更大的异常、不能抛出平级不一样的异常,但可以抛出一样的异常、更小的异常以及不抛出异常。
- 若父类中被重写的方法没有抛出异常时,则子类中重写的方法只能进行异常的捕获处理
- 若一个方法内部又以递进方式分别调用了好几个其它方法,则建议这些方法内可以使用抛出的方法处理到最后一层进行捕获方式处理
如:方法体所在的类中抛出异常,最后main()方法调用的时候try-catch捕获异常
自定义异常
- 概念:
当需要在程序中表达年龄不合理的情况时,而Java官方又没有提供这种针对性的异常,此时就需要自定义异常加以描述。 - 实现流程:
- 自定义xxxException异常类继承Exception类或者其子类
- 提供两个版本的构造方法,一个是无参构造方法,另外一个是字符串作为参数的构造方法
- 异常的产生:
throw new 异常类型(实参);
示例代码如下:
1. 异常类编写
public class AgeException extends Exception{
static final long serialVersionUID = -3387516993124229948L; // 用于序列化操作
public AgeException() {
}
public AgeException(String message) {
super(message);
}
}
2. 方法调用自定义异常类
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) throws AgeException {
if(age>0 && age<150) {
this.age = age;
} else {
throw new AgeException("年龄不合理!!!");
}
}
public Person() {
}
public Person(String name, int age) throws AgeException {
setAge(age);
setName(name);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3. 实现类操作:
public class PersonTest {
public static void main(String[] args) {
Person person = null;
try {
person = new Person("tb", -30);
} catch (AgeException e) {
e.printStackTrace();
}
System.out.println(person);
}
}