后续还会继续完善,有错误请指教。
---------------------10.10---------------------------
总结
- 1图异常分类;
- 5个关键字:Try(可能抛出异常的语句/试图捕获异常) catch(对try中可能抛出的不同异常类型做处理) finall(无论是否发生异常都会执行finally) throw(构造并抛出异常) throws(声明该方法可能抛出的异常)
- try、catch、finally、return执行顺序
- 先捕获小的,再大的
- 异常和重写的关系
异常概念
Java把异常当做对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。
异常分类
in java.lang.Object--java.lang.Throwable--Error错误、Exception异常(部分异常需程序员显式声明或捕获)
-可查异常和不可查异常
可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。
除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。
如果使用throw在方法体中抛出可查异常,则需要在方法头部声明方法可能抛出的异常类型。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
-编译异常(可查的异常)和运行异常(不可查的异常)
(1)运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
当出现RuntimeException的时候,我们可以不处理。当出现这样的异常时,总是由虚拟机接管。比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。
出现运行时异常后,如果没有捕获处理这个异常(即没有catch),系统会把异常一直往上层抛,一直到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。所以若不对运行时异常进行处理,后果严重,要么是线程中止,要么是主程序终止。
如果不想终止,则必须捕获所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。
(2)非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。如IOException、SQLException等以及用户自定义的Exception异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch并处理,否则程序就不能编译通过。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。
面对异常的消极措施-抛出异常
(此模块还需要完善添加,通过代码深入理解。自定义的异常暂时没思考)
抛出异常有三种形式,一是throw,一个throws,系统自动抛异常。
throw 就是抛出一个实际的异常,并获取这个异常的引用,这个异常会被抛到外部的环境,由外部环境进行处理。
throws是一个异常声明,它声明这个方法可能会抛出一个异常,注意是可能,所以在没有异常的情况下也是可以用throws的,而throws本身的作用也是用来提高程序的健壮性,反过来,如果这个方法的的确确的有一个异常,那么编译器会强制让你加上throws这个异常声明。
1)作用不同: throw用于程序员自行产生并抛出异常; throws用于声明在该方法内抛出了异常
2) 使用的位置不同: throw位于方法体内部,可以作为单独语句使用; throws必须跟在方法参数列表的后面,不能单独使用。
3)内容不同: throw抛出一个异常对象,且只能是一个; throws后面跟异常类,而且可以有多个。
面对异常的积极措施-捕获和处理
try语句
catch语句
在catch中声明的异常对象 catch(Exception e)封装了异常事件发送的消息,在catch语句中可使用这些对象e方法获取异常信息。如下:
getMessage(),得到有关异常事件的信息。
printStackTrace(),跟踪异常事件发生时,执行堆栈的内容。
JAVA中try、catch、finally带return的执行顺序总结
异常处理中,try、catch、finally的执行顺序是按顺序执行的。即,(1)如果try中没有异常,则顺序为try→finally,如果try中有异常,则顺序为try→catch→finally。且(2)无论出现什么情况,finally块中的内容都要被执行。(解释:在执行return语句之前,会先将返回值(复制一份)存储在一个指定的位置,其次再去执行finally中内容,最后返回之前保存的值。)
但有以下几种特殊情况需要注意:
一般情况:
public class TestFinally {
public static void main(String[] args) {
int result = testFinally();
System.out.println(result);
}
static int testFinally(){ //定义为static,否则报错!public不是必须要加的。
try{
return 1;
} catch (Exception e) {
e.printStackTrace();
// return 0;
}finally {
System.out.println("execute finally");
}
return 0; // 若无返回,会报错!或者将返回放在catch中
}
}
/*输出:
execute finally
1
*/
情况2:finally中改变return的值时,需要考虑返回值类型。若是对基本类型数据修改则不改变其返回值,但是对于引用类型的数据修改,则影响最终返回值。
public class TestFinally {
public static void main(String[] args) {
int result1 = testFinally1();
System.out.println(result1);
StringBuffer resultRef = testFinally2();
System.out.println(resultRef);
}
static int testFinally1(){ //定义为static,否则报错!
int result =1;
try{
result = 2;
return result;
} catch (Exception e) {
e.printStackTrace();
return 0;
}finally {
result = 3;
System.out.println("execute finally1");
}
}
static StringBuffer testFinally2(){
StringBuffer s = new StringBuffer("Hello");
try{
return s;
} catch (Exception e) {
e.printStackTrace();
return null;
}finally {
s.append("World");
System.out.println("execute finally2");
}
}
}
/*输出:
execute finally1
2
execute finally2
HelloWorld
*/
解释:return返回时不是直接返回变量的值,而是复制一份。
情况3:当finally中有return语句时,将会覆盖函数中其他return语句。即try /catch中的return会失效
public class TestFinally {
public static void main(String[] args) {
int result = testFinally();
System.out.println(result);
}
static int testFinally(){ //定义为static,否则报错!
try{
return 1;
} catch (Exception e) {
e.printStackTrace();
return 0;
}finally {
System.out.println("execute finally");
return 3;
}
}
}
/*输出:
execute finally
3
*/
情况4:java程序中的finally块,不一定被执行。
(1)try之前就出现异常语句;
(2)try块中强制退出。
public class TestException {
public static void main(String[] args) {
// int i = 100/ 0;
// 系统抛出异常 Exception in thread "main" java.lang.ArithmeticException: / by zero
try{
int i = 100/ 0;
System.out.print(i);
//System.exit(0); 报错,不执行finally,情况4
}catch(Exception e){
System.out.print("出现异常");
// throw new RuntimeException();
}finally{
System.out.print(2);
}
System.out.print(3);
}
}
/*
输出:出现异常23
*/
若catch到的不同异常类型之间存在继承,则应该先捕获小的异常。
public class TestException2 {
public static void main(String[] args) {
String[][] s = new String[5][];
try{
s[1][0] = "hello";
s[1][1] = "你好";
} catch (Exception e) {
// e.printStackTrace();
System.out.println("数组元素没有正确实例化");
}
try{
s[5] = new String[3];
s[5][1] = "hello";
} catch (ArrayIndexOutOfBoundsException e1) {
//e1.printStackTrace();
System.out.println("有异常发生了");
}
catch (Exception e2) {
//若将此catch块作为第一个catch,则报错:已经抛出异常,因为上面的是Exception的子类异常
e2.printStackTrace();
System.out.println("数组下标越界了");
}
}
}
/*输出:
数组元素没有正确实例化
有异常发生了
*/
重写方法需要抛出与原方法所抛出异常类型 一致或者不抛出异常。
常出的面试题-(用于自查)
异常处理的原理是什么
运行时异常和普通异常有什么区别
finally块中的代码什么时候被执行,是不是一定被执行?
常见的5个编译时异常和5个运行时异常?
throw和throws、try/catch的区别?
部分参考链接:https://www.cnblogs.com/diegodu/p/7298882.html