什么是异常?
java中的异常指的是:程序在运行过程中出现的错误,java具备处理异常的机制。java 中的Thorwable类是所有异常和错误的超类,有两个子类Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常,这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。
两种处理异常的方法:
1. 当前方法知道如何处理异常就采用try catch进行处理。将可能有异常的方法写进try语句里面,用catch处理异常。
2. 当前方法不知道处理异常就在定义该方法时抛出异常即可。
还是来看demo
public static double quotient(int numerator, int denominator) throws DivideByZeroException {
if (denominator == 0)
throw new DivideByZeroException();
else
return (double) numerator;
}
public static class DivideByZeroException extends ArithmeticException {
public DivideByZeroException() {
super("不能被0除");
}
创建了一类异常类,该类父类是算术异常类。在定义quotient方法时抛出DivideByZeroException异常,当传入的第二个参数是0就触发异常,输出提示信息。super(“不能被0除”);是调用父类的构造方法。在main方法里面做如下测试:
try {
double result = quotient(3, 0);
} catch (DivideByZeroException exception) {
System.out.println(exception.toString());
}
很明显结果会触发异常并且输出提示信息:不能被0整除。
关于java异常层次结构与分类(此图来源于互联网)
从上图可以看出异常分类层次结构,可以清楚看出父类与子类关系。
Java异常处理涉及到五个关键字,分别是:try、catch、finally、throw、throws。通常java异常的处理的步骤是:
try{
}catch(异常类型 异常的变量名)
}finally
{
}
当然在try与finally之间可以有多个catch进行捕捉异常,但是这些异常的捕捉也严格的顺序。看下面一个demo:
public static void main(String[] args) throws Exception {
int[] a = new int[5];
try {
a[10] = 1;
} catch (ArrayIndexOutOfBoundsException ae) {
System.out.println(ae);
} catch (ArrayStoreException ae) {
System.out.println(ae);
} catch (ArithmeticException ae) {
System.out.println(ae);
} finally {
System.out.println("发现了异常,并且处理它了!");
}
}
异常捕捉的顺序是首先捕获ArrayIndexOutOfBoundsException类型异常;然后捕获ArrayStoreException类型异常;最后捕捉ArithmeticException类型异常。总的来说如果是多个catch捕捉异常的话,正确的做法是从上到下异常类范围越来越广泛。比如说如果不知道最后一个抛出什么异常,那可以是Exception或者ERR。上面的demo捕捉的是:java.lang.ArrayIndexOutOfBoundsException: 10,属于数组范围边界异常。一直执行到最后finally 处理方法。
对throw、throws关键字的理解
throw关键字是用于方法体内部,用来抛出一个Throwable类型的异常。如果抛出了检查异常,则还应该在方法头部声明方法可能抛出的异常类型。该 方法的调用者也必须检查处理抛出的异常。看第一个demo代码。throws关键字用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常。仅当抛出了检查异常,该方法的调用者才必须处理或者重新抛出该异常。
用户自定义异常
除了java提供的常用异常处理类以外,用户还需要常常自定义自己所需要的异常类。比如说通过扩展算术异常或者其他类异常等。在对方法设计过程中需要考虑边界条件和运行条件的限制,使用异常可以使程序征程运行,减少bug,也给开发和调试带来诸多好处。