一、异常概述
int a =10;
int b =0;
int c =a/b;
System.out.println(c);
于是控制台出现了
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.javase.excepetion.ExceptionTest01.main(ExceptionTest01.java:7)
这个信息被我们称为异常信息,这个信息是JVM打印的。
(1)什么是异常,有什么用?
一下程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常。java语言是很完善的语言,提供了异常的处理方式,以下程序执行过程中出现了不正常情况,java把异常信息打印输出到控制台,供程序员参考,程序员看到异常信息之后,可以对程序,进行修改,让程序更加的健壮。
(2)异常以什么形式存在?
我们现在New一个异常
NumberFormatException n1 = new NumberFormatException("数字转换异常");
System.out.println(n1);
于是控制台便输出了
java.lang.NumberFormatException: 数字转换异常
所以我们发现异常是以类的形式存在的。
(3)异常结构图
(4)编译时异常和运行时异常的区别
)编译时异常发生的概率高,运行时异常发生的概率比较低。
编译时异常举例:
看到外面下雨了,出门的时候已经预料到,如果不打伞,可能会生病。拿一把伞就是对
生病异常发生之前的处理方式,对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
运行时异常举例:
小明走在街上,可能会被轮子砸到。因为这种概率低,所以没必要对它进行预处理。
二、异常的处理方式
(1)在方法声明的位置上,使用throws关键字,抛给上一级
为什么我的doSome()会报错呢?
因为它继承的父类这个,然而这个父类又继承了编译时的异常。
所以,会报错。
(2)第二种方法:采用try…catch()的方式进行捕捉
一般不建议在main方法上使用throws,因为这个异常如果真正发生了,一定会提供JVM,JVM只有终止。
(3)上报和捕捉的选择
如果系统调用者来处理,则采用上抛。其他情况使用捕捉的方式。
三、异常的两个方法
(1)getMessage()
//获取异常简单描述信息:这个信息实际上就是构造方法上面String参数
(2)printStackTrace();
//打印异常堆栈信息,java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的。
N1.printStackTrace();
就会打印出:
java.lang.NullPointerException: 异常
at com.javase.excepetion.ExceptionTest04.main(ExceptionTest04.java:5)
(3)如何利用异常printStackTrace()方法去调试
如何查看异常追踪信息?如何快速调试程序?
(a)从上往下看
(b)从这里往下看,因为上面是SUN公司写的一定不会有错误的
(c)灰色字体以上都是SUN公司编写的,所以就不用看了。
(d)看这蓝色字体的第一个,因为后面的蓝色字体全部都是因为第一个导致的。
四、深入try...catch
(1)代码执行顺序
从上面的例子可以看出,如果try中的f1发生了异常,直接走的是catch里面的方法,接着走try...catch后面的。
(2)可以多写几个catch
第一个catch是对f1的处理,第二个catch是对f1.read()的处理,但是catch在多写的时候,必须从上到下,遵循从下到大的原则。
(3)catch可以采用“|”的形式
(4)try…catch后面的会执行,不会因为发生了异常,然后就宕机了。
public static void main(String[]args){
try{
m1();
System.out.println("执行成功");
}catch(FileNotFoundException e){
e.printStackTrace();
}
System.out.println("HelloWorld");
}
private static void m1() throws FileNotFoundException{
m2();
}
private static void m2() throws FileNotFoundException{
m3();
}
private static void m3() throws FileNotFoundException{
new FileInputStream("C:\\Users\\赵晓东\\Desktop\\jdkapi1.8_google.CHM");
}
执行成功
HelloWorld
这个说明,我不会因为try...catch的执行,而影响后面。我HelloWorld照样执行。
五、try...catch中可以写finally
(1)关于try...catch中的finally子句:
(a)在finally子句中的代码是最后执行的,并且一定会执行的,即使try语句块中的代码出现了异常。
(b)finally语句通常使用在哪些情况下?
finally语句块中完成资源的释放/关闭,因为finally中的代码比较有保障,即使try语句块中的代码出现了异常,finally中的代码也会正常执行。
try{
//首先创建一个流对象。
FileInputStream f1 = new FileInputStream("C:\\Users\\赵晓\\Desktop\\jdkapi1.8_google");
//这时候s会出现空指针异常。
String s =null;
System.out.println(s.toString());
f1.close();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
分析以上程序,f1.close()是在String s=null;之后,如果String s=null;发生了空指针异常之后,fl.close();就不会执行了,这时候流不关闭,会浪费很大的内存。
所以根据以上条件,这时候就要使用finally语句了,也就是不论上面是否执行,我一定会执行我的finally语句。下面语句是我更改之后的。
(2)try和finally,没有catch行吗?
行,但是try不能单独使用。
从上面可以看出执行顺序是:先执行try,然后再执行finally,再执行return,所以放在finally语句中的代码一定会执行的。
但是,退出JVM之后,finally语句中的代码就不执行了。
(3)关于final、finally、finalize的区别
(a)final关键字
final修饰的类是无法继承的,final修饰的方法无法覆盖,final修饰的变量不能重新赋值。
(b)finally关键字
和try一起联合使用
finally语句块中的代码是必须执行的。
(c)finalize标识符
是一个object类中的方法名,这个方法是由垃圾回收器GC负责调用的。
(4)finally面试题
以下程序的结果会输出什么?
答案是100,你一定很纠结,那么我们来看一下反编译的代码
public static int m(){
int i =100;
int j=i;
i++;
return j;
}
总结:以前不知道异常是什么,感觉特别的神奇,现在终于明白了,它就是一个普普通通的类,这个类在不合适逻辑的情况下,会报。我们也可以根据自己的业务写异常,写异常的时候直接继承Exception,然后再写两个构造方法,其中有一个String参数的构造方法,这个构造方法其实是调用了getMessage()方法。还有就是异常的处理两种方式,一种是上抛,一种是采用try...catch的形式进行捕捉,如果你想让调用者处理,你就用第一种t上抛的形式,其余都用try...catch。然后try...catch是能和finally进行试用的,比如我们在最后进行关闭资源的时候,可以把方法写到finally里面。