java异常
Java把异常当作对象来处理,并定义一个基类 java.lang.Throwable 作为所有异常的超类。
在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。
Java异常层次结构图:
从图中可以看出所有异常类型都是内置类 Throwable 的子类,因而 Throwable 在异常类的层次结 构的顶层。
接下来Throwable 分成了两个不同的分支,一个分支是Error,它表示不希望被程序捕获或者是程序 无法处理的错误。另一个分支是Exception,它表示用户程序可能捕捉的异常情况或者说是程序可以处理的异常。
其中异常类 Exception 又分为运行时异常( RuntimeException )和非运行时异常。Java异常又可以分为不受检查异常( Unchecked Exception )和检查异常( Checked Exception )。
Error
Error 类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
比如说:
Java虚拟机运行错误( Virtual MachineError ), 当JVM不再有继续执行操作所需的内存资源时, 将出现 OutOfMemoryError(内存异常) 。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止;
对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状 况。在Java中,错误通常是使用 Error 的子类描述。 (本质上error错误发生的时候,交给虚拟机去处理终止线程即可).
Exception
在 Exception 分支中有一个重要的子类 RuntimeException (运行时异常),该类型的异常自动为你所编写的程序定义 ArrayIndexOutOfBoundsException (数组下标越界)、 NullPointerException (空指针异常)、ArithmeticException (算术异常)、 MissingResourceException (丢失资源)、 ClassNotFoundException (找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处 理,也可以不处理。
这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;而 RuntimeException 之外的异常我们统称为非运行时异常,类型上属于 Exception 类及其子类.
注意
Error 和 Exception 的区别: Error 通常是灾难性的致命的错误,是程序无法控制和 处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程; Exception 通常情况下是可 以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
检查异常和不受检查异常
检查异常:在正确的程序运行过程中,很容易出现的、情理可容的异常状况,在一定程度上这种异常的 发生是可以预测的,并且一旦发生该种异常,就必须采取某种方式进行处理。
解析:除了RuntimeException及其子类以外,其他的Exception类及其子类都属于检查异常,当程序 中可能出现这类异常,要么使用try-catch语句进行捕获,要么用throws子句抛出,否则编译无法通 过。
不受检查异常:包括RuntimeException及其子类和Error。
检查异常:除了RuntimeException及其子类以外,其他的Exception类及其子类都属于检查异常
分析: 不受检查异常为编译器不要求强制处理的异常, 检查异常则是编译器要求必须处置的异常。
异常处理五个关键字
分别是: try 、 catch 、 finally 、 throw 、 throws
try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常 时,异常就被抛出。
catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。
finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络 连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语 句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
throw – 用于抛出异常。
throws – 用在方法签名中,用于声明该方法可能抛出的异常。
异常处理:try-catch-finally
finally语句不是必要的
public static void main(String[] args) {
int a=0;
int b=1;
// System.out.println(b/a);//出现ArithmeticException异常
//可以采用try-catch处理异常来处理
try{ //try监控
System.out.println(b/a);
}catch(ArithmeticException e){ //异常捕获,catch(想要捕获的异常类型)
//这里是捕获(1/0)出现的ArithmeticException异常,所以catch(ArithmeticException e)
//如果是更高一层的错误,就不行了,要换成更高的错误类型,也就是说抛到更高级的异常去处理
System.out.println("程序出现异常,a不能为0");
}finally{
System.out.println("finally");
}
}
异常处理:try-catch(多个catch语句块匹配不同的异常类型)-finally
下述的语句块因为无限递归而导致栈溢出的错误。我们可以
public class test2 {
public static void main(String[] args) {
new test2().a();
}
public void a(){
b();
}
private void b() {
a();
}
}
catch里面异常捕获类型应该上升到error,y栈溢出属于error错误,然后多个catch的时候,应该按照异常类型从小到大写。
public class test2 {
public static void main(String[] args) {
try {
new test2().a();
} catch (ArithmeticException e) {
System.out.println("不能这样的除法");
//e.printStackTrace();//打印错误信息
} catch (Error e) {
System.out.println("不能这样递归");
//e.printStackTrace();//打印错误信息
} catch (Throwable e) {
System.out.println("不能这样错误");
//e.printStackTrace();//打印错误信息
} finally {
System.out.println("finally");
}
}
public void a() {
b();
}
private void b() {
a();
}
}
主动的抛出异常
public class test2 {
public static void main(String[] args) {
int a = 0;
int b = 1;
new test2().test(b,a);
}
public void test(int a, int b) {
if (b == 0) {
throw new ArithmeticException(); //主动抛出异常,在方法中使用
}
}
}
public class test2 {
public static void main(String[] args) {
int a = 0;
int b = 1;
try {
new test2().test(b,a);
} catch (ArithmeticException e) {
// e.printStackTrace();//打印异常的信息
System.out.println("出现了异常");
} finally {
System.out.println("finally");
}
}
//假设在这个方法中,处理不了这个异常的时候,或在方法上抛出异常
public void test(int a, int b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException();//主动抛出异常,在方法体里写
}
}
}
输出:
出现了异常
finally
try, catch,finally ,return 执行顺序
1.执行try,catch , 给返回值赋值
2.执行finally
3.return