Java之异常处理
1、异常的定义和体系结构
异常是在程序中导致程序中断运行的一种指令流。
现有代码如下:
public static void main(String argsp[]){
int a = 10 ;
int b = 0 ;
int temp = a / b ; // 进行除法运算
System.out.println("temp = " + temp) ;
System.out.println("============= 计算结束 =============") ;
}
当程序运行时,控制台显示的内容为 Exception in thread "main" java.lang.ArithmeticException: / by zero at ExceptionDemo01.main(ExceptionDemo.java:5),这段文字表示代码在 int temp =a / b;的位置发生了异常,而后面的输出语句并没有输出,所以异常导致了该程序没有执行完毕就退出了。
接下来看下异常的体系结构:
异常指的是Exception , Exception类, 在Java中存在一个父类Throwable(可能的抛出)
Throwable存在两个子类:
1.Error:表示的是错误,是JVM发出的错误操作,只能尽量避免,无法用代码处理。
2.Exception:一般表示所有程序中的错误,所以一般在程序中将进行try…catch的处理。
通常异常又分为两类:受检异常和非受检异常
非受检异常指的是java.lang.RuntimeException和java.lang.Error类及其子类,所有其他的异常类都称为受检异常。受检异常必须处理来避免编译上的错误,而非受检异常可以处理也可以不处理。
2、异常的处理
异常的处理有两种方式,一种是捕获,一种是抛出。
首先来看看异常发生时的步骤:
1.发生异常(JVM根据异常的情况,创建了一个异常对象-包含了异常信息)
2.发生异常的发放没有对异常进行处理,自动将异常抛给方法的调用者,直到抛给main的调用者JVM
3.JVM对异常信息进行了响应(将异常信息显示到控制台,中断处理)
处理:
捕获异常的语法:
try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){try+catch的处理流程
finally
异常体系结构
// 异常的处理操作
} ...
finally{
// 异常的统一出口
}
finally中的语句不管代码是否产生 了异常,最终都要执行此段代码,不过还是有一些情况是不会执行的,请看下面的面试题。
try+catch的处理流程:
1. 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
2. 那么,此时如果异常发生在try语句,则会自动找到匹配的catch语句执行,如果没有在try语句中,则会将异常抛出.。
3. 所有的catch根据方法的参数匹配异常类的实例化对象,如果匹配成功,则表示由此catch进行处理。
注意点:捕获更粗的异常不能放在捕获更细的异常之前,如果为了方便,可以用Exception捕获所以的异常
特殊的多异常捕获写法:
catch(异常类型1 |异常类型2 对象名){
//表示此块用于处理异常类型1 和 异常类型2 的异常信息
}
抛出异常(throw和throws关键字):
throw关键字表示在程序中人为的抛出一个异常,因为从异常处理机制来看,所有的异常一旦产生之后,实际上抛出 的就是一个异常类的实例化对象,那么此对象也可以由throw直接抛出。 代码格式如下:
throw new Exception("XXXXXXXXXXXXXX") ;
throws关键字,主要在方法的声明上使用,表示方法中不处理异常,而交给调用处处理。代码格式如下:
返回值 方法名称()throws Exception{
}
3、自定义异常类
编写一个类, 继承Exception,并重写一参构造方法 即可完成自定义受检异常类型。 编写一个类, 继承RuntimeExcepion,并重写一参构造方法 即可完成自定义运行时异常类型。 例如:
class MyException extends Exception{ // 继承Exception,表示一个自定义异常类
public MyException(String msg){
super(msg) ; // 调用Exception中有一个参数的构造
}
};
使用:
MyException e = new MyException("message");
throw e;
自定义异常可以做很多事情, 例如:
class MyException extends Exception{
public MyException(String msg){
super(msg) ;
//在这里给维护人员发短信或邮件, 告知程序出现了BUG。
}
};
使用:
返回值 方法名称()throws MyException{
...
MyException e = new MyException("message");
throw e;
...
}
4、异常处理常见面试题
1. try-catch-finally 中哪个部分可以省略?
答: catch和finally可以省略其中一个 , catch和finally不能同时省略;当省略了catch,就不会捕获异常了,那么就没意义了
2. try-catch-finally 中finally中的语句一定会执行吗?
答:不一定会执行,有两种情况。第一种是当遇到程序中断,电脑关机,停电等外部因素时,finally中的语句就不会执行了;第二种是在进入finally语句前,遇到了System.exit(0);这段代码,那么就会直接正常退出程序,结束当前正在运行中的java虚拟机,finally中的语句也就不会再执行了。
3.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
答:finally中的代码会执行
详解: 执行流程: 1. 先计算返回值, 并将返回值存储起来, 等待返回
2. 执行finally代码块
3. 将之前存储的返回值, 返回出去;
需注意: 返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不会改变,前提是基本数据类型。如果返回的是引用类型,那么存储起来的则是引用类型对象的内存地址,对象里面的属性还是可以改变的。见代码:
public class Test {
public static void main(String[] args) {
int x = sum(3,3);
System.out.println(x);//输出结果为:6
Student s = getStu("李斯",23);
System.out.println(s.toString());//输出结果为:姓名:李斯,年龄:17
}
public static int sum(int a,int b){
int c = a + b;//计算a+b
try{
return c;//返回c的值
}catch (Exception e){
return 0;
}
finally {
c = 10;//修改c的值
}
}
public static Student getStu(String name,int age){
Student student = new Student(name,age);
try{
return student;
}catch (Exception e){
return null;
}finally {
student.setAge(17);//修改student中的年龄
}
}
}
class Student{
private String name;
private int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setAge(int age){
this.age=age;
}
public String toString(){
return "姓名:" + name + ",年龄:" + age;
}
}
有问题欢迎指正