一、什么是异常
1)如果JVM检测出不可能执行的操作,就会出现运行时错误。java中运行时错误将作为异常抛出。
2)异常就是一个从异常类创建的对象,表示阻止正常进行程序执行的错误或者情况
二、异常处理的概念
1)异常是从方法抛出的。方法的调用者可以调用以及处理该异常
2)当异常被抛出时,正常的执行流程就被中断。抛出异常是将异常从一个地方传到另一个地方
3)一个异常可能是通过try块中的throw语句直接抛出,或者调用一个可能会抛出异常的方法而抛出
4)异常处理最根本的优势:将检测错误(由被调用的方法完成)从处理错误(由调用方法完成)中分离出来
三、异常类型
1)异常类型的根类是Throwable
2)异常类分为三种主要类型:系统错误(Error),异常(Exception),运行时异常(RuntimeException)
3)系统错误是内部系统的错误。没办法,只能终止程序。
4)异常,是程序和外部环境所引起的错误,这些错误能被程序捕获和处理。比如说ClassNotFoundException
5)运行时异常,描述程序设计错误,例如错误的类型转换、访问一个越界数组
5)免检异常:RuntimeException、Error以及它们的子类
6)必检异常:编译器强制程序员检查,并通过try-catch块处理它们,或者在方法头声明
四、异常处理
1)声明异常:每个方法都必须声明它可能抛出的必检异常的类型
1.1)不要求显式声明Error和RuntimeException这些免检异常
1.2)声明异常的格式: public returnType methodName() throws Exception1, Exception2,...ExceptionN
例子: public void myMethod() throws IOException
1.3)注意:如果方法没有在父类中声明异常,那么就不能在子类中对其进行继承来声明异常
2)抛出异常
2.1)定义:检测到错误的程序可以创建一个适合的异常类型的实例并抛出它
2.2)每个异常类至少有两个构造方法,一个无参,一个有参String
例子: throw new IllegalArgumentException("Wrong Argument")
2.3)注意:声明异常是throws,抛出异常是throw
3)捕获异常
try{
statements;
}catch(Exception1 e1){
handler for exception1
}
catch(Exception2 e2){
handler for exception2
}
4)捕获异常的要点
一个例子即可知道
假设下面的语句中,statement2可能会引起一个异常
try{
statement1;
statement2;
statement3;
}catch(Exception1 ex1){
statement6;
}catch(Exception2 ex2){
throw e2;
}finally{
statement4;
}
statement5;
4.1)如果没有异常发生,会执行statement4吗?会执行statement5吗?会执行statement3吗?
会,会,会
4.2)如果异常类型是Exception1,那么会执行statement4吗?会执行statement5吗?会执行statement3吗?
会,会,不会
4.3)如果异常类型是Exception2,那么会执行statement4吗?会执行statement5吗?会执行statement3吗?
会,不会,不会
4.4)如果异常类型不是Exception1以及Exception2类型,那么会执行statement4吗?会执行statement5吗?会执行statement3吗?
会,不会,不会
原因:
1)try某一条语句出现异常,那么try里面剩下的语句都不执行。。比如上面的statement3
2)如果try里面出现的异常,能被catch捕获处理,那么这个catch里面的语句能执行(比如上面的statement6),并且try-catch块后面的语句也能执行,比如上面的statement5
3)如果try里面出现的异常,被catch捕获了,但是它又抛出了,那么这个catch里抛出之前的语句能执行,抛出之后的语句不能执行。并且try-catch块后面的语句也不能执行
4)如果try里面出现的异常,不能被catch捕获,那么try-catch块后面的语句也不能执行
5)finally什么时候都执行,即使try或者catch里面有return语句
没个具体的例子怎么行呢?下面就是个可运行的例子
public class Test {
public static void main(String[] args) {
int[] a = {1, 0};
//测试1
calc(a, 0, 1);
//测试2
//calc(a, 0, 2);
}
public static void calc(int[] a, int i, int j){
try{
System.out.println("我是第一条语句");
int num = a[i] / a[j];
System.out.println("我是第三条语句");
}catch(ArithmeticException e){
System.out.println("捕获到除0异常");
}catch(IndexOutOfBoundsException e2){
System.out.println("抛出到下标越界异常");
throw e2;
}finally{
System.out.println("到了finally");
}
System.out.println("到了最后一句");
}
}
五、链式异常
1)定义:catch块重新抛出原始异常时,有时候需要同原始异常一起抛出一个新异常(带有附加信息),这称为链式异常
2)例子:
package test;
public class Test {
public static void main(String[] args) {
try{
method1();
}catch(Exception ex){
ex.printStackTrace();
}
}
public static void method1() throws Exception{
try{
method2();
}catch(Exception ex){
throw new Exception("New info from method1", ex);
//试试下面这句不加ex的,会有什么不同。
//throw new Exception("New info from method1");
}
}
public static void method2() throws Exception{
try{
int i = 1 / 0;
}catch(Exception ex){
throw new Exception("New info from method2");
}
}
}
2.1)加上ex(是链式异常)的结果如下:
java.lang.Exception: New info from method1
at test.Test.method1(Test.java:16)
at test.Test.main(Test.java:6)
Caused by: java.lang.Exception: New info from method2
at test.Test.method2(Test.java:26)
at test.Test.method1(Test.java:14)
... 1 more
2.2)不加的结果如下:
java.lang.Exception: New info from method1
at test.Test.method1(Test.java:18)
at test.Test.main(Test.java:6)
六、自定义异常
1)java提供了很多的异常类,一般来说,尽量去使用它们,不要创建自己的异常类。。但我就是想定义自己的异常,又怎么办呢
2)那就去继承Exception类或者它的子类
例子:
public class InvalidRadiusException extends Exception{
private double radius;
public InvalidRadiusException(double radius){
super("Invalid radius " + radius);
this.radius = radius;
}
public double getRadius(){
return radius;
}
}
怎么用上面的例子呢?其他异常怎么用,你就怎么用。下面给个调用的例子
if(newRadius < 0){
throw new InvalidRadiusException(newRadius);
}
3)继承RuntimeException可以吗?
可以,但是它会使得自定义异常,成为免检异常。
我们最好使自定义异常必检,这样,编译器就可以在程序中强制捕获这些异常