异常
编程时往往会遇到程序异常的情况,在Java中,通过面向对象方法处理异常,发生异常就是产生一个异常对象,所以异常和错误是不同的。
概念
-
Throwable:Java中所有异常类型都是内置类java.lang.Throwable类的子类,位于异常层次机构的顶层。
-
错误(Error):JVM无法语预期的错误,属于JVM层次的严重错误,一般是由JVM抛出。导致JVM无法继续执行,所以这是无法捕获或修复的,即程序员不能通过代码处理的,一般这种情况就是保证程序安全退出。比如虚拟机错误、内存溢出、线程死锁等。
-
异常(Exception):Exception及它的子类,可以被Java异常处理机制使用,可恢复可捕获,是异常处理的核心。
-
运行时异常:javac在编译时,不会提示发现这样的异常,对于这些异常编译可以通过,但程序不会处理运行时异常,出现这类异常,程序会停止。例如:
算数异常( java.lang.ArithmeticException: / by zero)、
指定的类不存在(java.lang.classnotfoundexception)、
数组索引越界(java.lang.arrayindexoutofboundsexception)、
空指针异常(java.lang.nullpointerexception)等。这些异常应该通过修正代码,而不是通过异常处理器处理,因为多半是代码编写有问题。
-
非运行时异常:javac强制要求程序员为这样的异常做预处理工作(使用try...catch,,,finally或者throws)。在方法中使用try...catch语句捕获并处理,或者用throws字句声明抛出它,否则无法编译通过。这样的异常一般与运行环境导致,因为程序可能被运行在各种未知的环境下,而程序员无法干预用户使用程序,所以应该为这样的异常时刻准备着。如SQLException、IOException、ClassNotFoundException等。
-
另一种叫法:检查和非检查异常,这是对于javac(编译器)来说的,是否运行编译通过这样的异常。
检查异常(checked exception)除Error和Runtime 的其他异常,javac强制要求为这样的异常做预备处理(try...catch或throws)否则编译不通过。
非检查异常:Error和RuntimeException及其子类。不提示发现这样的异常,不在程序处理这些异常(可以处理也可以不处理)
异常处理
抛出异常
- 当一个方法出现错误并引发异常时,方法就会创建异常对象并交付运行时系统。
- 异常对象包含异常类型和异常出现时的程序状态等异常信息。
- 运行时系统负责寻找处理异常的代码并执行。
- 抛出异常的方法:throw和throws
捕获异常
- 由于运行时异常(RuntimeException)的不可查性,运行时异常由,Java运行时系统自动抛出,允许应用程序忽略运行时异常。
- 对于方法运行中可能出现的错误(Error),当运行方法不想捕获时,Java允许该方法不做任何抛出声明,因为多数Error异常属于永远不能被允许发生的情况,即合理的应用程序不该捕获的异常。
- 对于所有的可查异常,当一个方法选择不捕获可查异常时,它必须声明或抛出异常。
- 总之,对于可查异常必须捕获或者声明抛出,允许忽略不可查的运行时异常和错误
关键字
throw和throws
throw
throw用于明确抛出一个异常对象,语句抛出一个异常。声明在方法体内
throw e; //throw (异常对象);
抛出一个异常类的实例化对象。try语句要捕获一个异常对象,那么这个异常对象可以是自己抛出的。
public class Test4 {
public static void main(String[] args) {
try {
throw new Exception("这是自己throw抛出一个异常对象");
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
}
}
throws
throws属于异常处理的一种方式,声明在方法的声明处,表示此方法不处理异常,交给方法调用者处理。
public void test(int i) throws Exception1,Exception2 { //... }
throws Exception , Exception 2 只是告诉程序这个方法可能会抛出这些异常,方法的调用者可能要处理这些异常,而Excepton1,Exception2这些异常可能是由该函数体产生的。
public class Test3{
public static void test(int i) throws Exception {
int a = 5/i ;
System.out.println(a);
}
public static void main(String[] args) throws Exception {
test(0);
/**
输出结果: 算数异常
Exception in thread "main" java.lang.ArithmeticException: / by zero
*/
}
}
在本程序中,主方法(main)不处理任何异常,而是交给JVM,所以在主方法使用throws表示交给JVM处理。在主方法中,所有异常都可以不使用try...catch处理异常。
区别一下
- throws用在方法声明后,表示再抛出异常,throws将异常抛给上一级,由方法调用者处理。
- throw在方法体中,抛出异常,并且throw后语句不执行,必须使用try...catch(finally可以用,也可以不用)。
- throws表示出现异常的可能性,throw则是抛出异常,一定抛出某种异常。
e.printStackTrace();
API:将此 throwable 及其追踪输出至标准错误流。即:
在命令行打印异常信息在程序中出错的位置及原因。
finally
关于finally在另一篇文章里 finally相关问题(finally块中的代码,真的是一定执行吗?)
需要注意的地方
- try块、catch块、finally块中的局部变量、异常变量他们之间不可共享使用。
- 每一个catch块用于处理一个异常,按照顺序从上到下匹配异常,只有第一个匹配的catch会执行,所以父类异常要放在后面。
public class Test3{
public static void test(int i){
int a = 5/i ; //异常抛出点
System.out.println("test"); //未执行
}
public static void main(String[] args) {
try{
test(0);
}
catch (NullPointerException e1){
System.out.println("空指针异常");
}
catch (ArithmeticException e2){
System.out.println("算数异常");
}finally {
System.out.println("finally");
}
/**
* 输出结果:
* 算数异常
* finally
*/
}
}
-
test方法中遇到异常抛出点,就执行异常处理,后面的语句不会执行。
-
异常处理的任务就是将执行控制流,从异常发生的地方转移到能够处理这种异常的地方去。所以当某条语句发生异常后,这条语句后面将不会执行,失去了焦点。执行流跳转到匹配的异常处理catch代码块去执行。
-
Java在处理后,让执行流恢复到处理了异常的catch块后接着执行,这种策略叫做终结式异常处理模式
我的csdn:https://blog.csdn.net/weixin_45910779/article/details/113778266