异常:由于操作不规范、输入不符合要求、资源找不到等异于平常的情况,会导致程序出错。导致程序不正常运行。异常类型最高的继承类是Throwable,下面有2个子类
Error:指的是JVM错误,这时的程序并没有执行,无法处理
Exception:
编译时异常:不是RuntimeException的异常, 必须明确处理(捕捉或抛出);在写java源文件时,如果不对其进行处理,则编译都无法通过的异常。
运行时异常:RuntimeException异常, 在写代码的时候,不会报错的。只有在代码运行的时候,由于考虑不周,才有可能出现的异常。(可以不处理,但是一旦发生,程序就不能继续运行) 这个需要程序员特别的注意。
处理方式有两种:
1、try catch捕捉异常
public class TestException {
public static void main(String[] args) {
File f= new File("d:/LOL.exe");
//将可能抛出FileNotFoundException 文件不存在异常的代码放在try里
try{
//如果文件存在,就会顺序往下执行,并且不执行catch块中的代码
System.out.println("试图打开 d:/LOL.exe");
new FileInputStream(f);
System.out.println("成功打开");
}
//如果文件不存在,try 里的代码会立即终止,程序流程会运行到对应的catch块中
catch(FileNotFoundException e){
System.out.println("d:/LOL.exe不存在");
// e.printStackTrace(); 会打印出方法的调用痕迹,如此例,会打印出异常开始于TestException的第16行,这样就便于定位和分析到底哪里出了异常
e.printStackTrace();
}finally{
System.out.println("无论文件是否存在, 都会执行的代码");
}
}
}
注意:
a:try里面代码越少越好。
b:catch里面必须有内容,哪怕是给出一个简单的提示。
c:一旦try里面出了问题,就会在这里把问题给抛出去,然后和catch里面的问题进行匹配,一旦有匹配的就执行catch里面的处理,然后结束了try...catch继续执行后面的语句。
d:能明确异常的尽量明确异常
e:平级关系的异常谁前谁后无所谓,如果出现子父关系,父必须在后面
2、直接抛出异常throws
如果程序出现问题,我们没有做任何处理,最终JVM会做出默认的处理。把异常的名称,原因以及出现的问题等信息输出在控制台。同时会结束程序
小demo:
主方法调用method1,method1调用method2,method2中打开文件,method2中需要进行异常处理
但是method2不打算处理,而是把这个异常通过throws抛出去,那么method1就会接到该异常。 处理办法也是两种,要么是try catch处理掉,要么也是抛出去。method1选择本地try catch住 一旦try catch住了,就相当于把这个异常消化掉了,主方法在调用method1的时候,就不需要进行异常处理了
public class TestException {
public static void main(String[] args) {
method1();
}
private static void method1() {
try {
method2();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void method2() throws FileNotFoundException {
File f = new File("d:/LOL.exe");
System.out.println("试图打开 d:/LOL.exe");
new FileInputStream(f);
System.out.println("成功打开");
}
}
注:
throws与throw这两个关键字接近,不过意义不一样,有如下区别:
1. throws 出现在方法声明上,而throw通常都出现在方法体内。
2. throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某个异常对象。
3.尽量不要在main方法上抛出异常,编译期异常抛出,将来调用者必须处理,运行期异常抛出,将来调用可以不用处理
自定义异常throw: 如果出现了异常情况,我们可以把该异常抛出,这个时候抛出的应该是异常的对象,一些特殊情况会使用自定义异常如仓库库存不能为负数,年龄不能超过200岁等。
public class Hero {
public String name;
protected float hp;
public void attackHero(Hero h) throws EnemyHeroIsDeadException{
if(h.hp == 0){
throw new EnemyHeroIsDeadException(h.name + " 已经挂了,不需要施放技能" );
}
}
public String toString(){
return name;
}
class EnemyHeroIsDeadException extends Exception{//自定义异常,继承Exception
public EnemyHeroIsDeadException(){
}
public EnemyHeroIsDeadException(String msg){
super(msg);
}
}
public static void main(String[] args) {
Hero garen = new Hero();
garen.name = "盖伦";
garen.hp = 616;
Hero teemo = new Hero();
teemo.name = "提莫";
teemo.hp = 0;
try {
garen.attackHero(teemo);
} catch (EnemyHeroIsDeadException e) {
// TODO Auto-generated catch block
System.out.println("异常的具体原因:"+e.getMessage());
e.printStackTrace();
}
}
}
经典面试题:
面试题:throws和throw的区别
throws:
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw:
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
finally 的特点及作用
特点:被finally控制的语句体一定会执行
注意:在执行到finally之前,JVM虚拟机退出了(如System.exit(0))
作用:用于释放资源
面试题1:final、finally和finalize的区别?
final:最终的,可以修饰类,成员变量。成员方法
修饰类,类不可以被继承
修饰变量,变量是常量
修饰方法,方法不能被重写
finally:是异常处理的一部分,用于释放资源
一般来说,代码肯定会执行,特殊情况:在执行到finally之前,JVM退出了
finalize:是Object类的一个方法,用于垃圾回收
面试题2:如果catch里面有return语句,请问finally里面的代码还会执行吗?如果会,请问是在return前还是return后。
会在return前执行。准确的说是在中间
编译时异常和运行时异常的区别
编译时异常:JAVA程序必须显示处理,否则程序就会发生错误,无法通过编译
运行时异常:无需显示处理,也可以和编译时异常一样处理