在正式讲之前我们先看几个例子 :
public class Test {
public static void main(String[] args) {
int a = 10 / 0;
System.out.println(a);
}
}
在我们平常写代码时,有时出现这样的错误,这就是异常!
并且发生错误之后,程序就被终结了,下面的代码都不会再执行了!
public class Test {
public static void main(String[] args) {
int[] array = null;
System.out.println(array.length);
System.out.println("java异常");
}
}
异常其实就是类.
异常 分为 : 编译时异常(受查异常) 和 运行时异常(非受查异常)
在java中除了异常还有错误.
我们先来简单说一下错误 : 列入栈溢出
error:类包括一些严重的程序不能处理的系统错误类.
public class Test {
public static void fun () {
fun();
}
public static void main(String[] args) {
fun();
}
}
那么异常呢?
在之前的章节中我们讲到了 拷贝类 Cloneable , 不知道还记不记的.
class A implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
A a = new A();
A b = (A)a.clone();
}
}
在这个代码中 CloneNotsupportedException 这就是一个受查异常.
这幅图中我们只显示了一部分,我们主要看一下重要的几个类.
上面的图,我标注了受查异常和运行时异常,它们都继承了Exception类.
大家重点记一下运行时异常RuntimeException 和 Exception 这两个类,进行来我们来定义几个异常类! 带大家感受一下 :
class NameException extends RuntimeException {
}
public class Test {
public static void main(String[] args) {
String name = "zhong";
if (!name.equals("chao")) {
throw new NameException();
}
}
}
这个类也可以去重写RuntimeException的方法(不是必须重写)
class NameException extends RuntimeException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
我们创建了一个类 并且继承了 RuntimeException ,并且在main方法中我们去触发了这个异常!
在main方法中的if语句去抛出了这个异常: 运用到了throw这个关键字
注意事项 :
1.throw必须写在方法体的内部.
2.抛出的对象必须是Exception 或者 Exception 的子类对象
3.如果抛出的是RuntimeException 或者 RuntimeException 的子类,则可以不用处理,直接交给JVM处理
4.如果抛出的是编译时异常,用户必须处理,否则不能通过编译
5.异常一旦抛出,其后的代码就不会执行.
我先把注意事项标出来 : 在下面我会一 一讲解到 :
现在我们来分析一下 : NametimeException 继承的 是 RuntimeException ,上面我们说到RuntimeException是运行时异常!
那么受查异常呢?
我们先抛总结 : 如果继承的是Exception那么它就是一个(编译时异常)受查异常.
如果继承的是RuntimeException 那么它就是运行时异常(非受查异常).
并不是说只能继承这两个异常! 我们还可以继承它们的子类!我想强调的是Exception是所有受查异常的" 父类 " , RuntimeException 是所有运行时异常的 " 父类 ".
再回到上面的代码中,为什么NameException类继承了Exception类,而下面的throw就会报红线呢?
这就不得不说到,受查异常和非受查异常的区别了 :
在注意事项中的 第三点 和 第四点中我们可以知道运行时异常我们不用去处理,但是编译时异常我们必须去处理!那么怎么处理呢?
很简单,那个方法体里面去抛这个异常了那么它就需要在它的方法体后面去声明这个异常(表示这个方法内部可能会抛出一个异常).
上面的代码可以修改为这样 :
如果在方法体中去抛一个运行时异常的类,则可以不去声明.
那么我们能不能自己去处理异常呢?总不能每次抛出异常后,把它交给JVM处理吧 ! 那样的话我们的代码就会被终结,不能进行执行下去了 !
因此我们在这里就要自己去处理异常 !
class NameException extends Exception {
}
public class Test {
public static void main(String[] args){
try {
String name = "zhong";
if (!name.equals("chao")) {
throw new NameException();
}
}catch (NameException e) {
e.printStackTrace();
System.out.println("捕捉到了 NameException 异常!!!!");
}
System.out.println("之后的代码!!");
System.out.println("就可以继续打印了");
}
}
try紧跟的后面的花括号里面存放的就是可能会抛出异常的代码
而catch()括号里面写的就是可能被抛出的异常类型,catch后面的花括号里面可以写一些输出语句来提醒触发了什么异常,
也可以写这一句 :
通过异常类型的变量 . printStackTrace() 就可以打印出这种红字提示 :
有两点需要注意 :
1. 当我们实现try catch 之后, 如果在try catch 这个语句中解决了要抛出的异常那么这个方法后面就不需要再去声明抛出的异常了!
2.如果catch里面是受查异常类型 并且它没有检测到你的try里面会抛出这个异常,那么它就会报错!
错误写法 :
原因在于 : 这个程序不会执行到第二个catch(),不论try里面出现什么异常都会被第一个catch()接收,Exception是所有异常类的父类,他能捕获所有的异常.
如果try当中出现了多个异常,那么会不会捕捉到多个异常?它的捕捉顺序是什么?
如果try中出现了多个异常,程序从上往下执行,谁先抛出异常就捕获那个异常.
不会抛出多个异常,在同一时间只会抛出一个异常!
class NameException extends Exception {
}
public class Test {
public static void main(String[] args){
try {
int[] array = null;
System.out.println(array.length);
int a = 10 / 0;
System.out.println("after");
}catch (ArithmeticException e) {
e.printStackTrace();
System.out.println("捕捉到了 ArithmeticException 异常!!!!");
} catch (NullPointerException c) {
System.out.println("捕捉到了 NullPointerException 异常");
}
System.out.println("之后的代码!!");
System.out.println("就可以继续打印了");
}
}
异常中还有一个关键字 finally :
1.不管try中的异常是否被catch捕捉,finally里的语句终会被执行.
2.finally一般用来对资源的释放(例如Sacnner) 可以把它写进try().这样finally会自动释放Scanner开辟的资源,不用通过scanner.close()进行释放了.
class NameException extends Exception {
}
public class Test {
public static void main(String[] args){
try(Scanner scanner = new Scanner(System.in)) {
int[] array = null;
System.out.println(array.length);
int a = 10 / 0;
System.out.println("after");
}catch (ArithmeticException e) {
e.printStackTrace();
System.out.println("捕捉到了 ArithmeticException 异常!!!!");
} catch (NullPointerException c) {
System.out.println("捕捉到了 NullPointerException 异常");
} finally {
//一般用来对资源的释放
System.out.println("不管try中是否会抛出异常,finally里的语句终将会执行!!");
}
System.out.println("之后的代码!!");
System.out.println("就可以继续打印了");
}
}
最后 : 总结一下异常的处理流程 :
大家有不懂的可以私信我,希望可以帮到大家~~~~~~~~~~~~