异常处理Exception
1、什么是异常处理?
异常是指程序在运行过程中出现的非正常现象,例如用户输入错误、除数为零、读取的文件不存在、数组下标越界等。发生异常时,程序终止运行。
示例1:
public class Demo1 {
public static void main(String[] args) {
int i=1,j=0,res;
System.out.println("begin");
res =i/j;
System.out.println("end");
}
}
结果:
begin
Exception in thread “main” java.lang.ArithmeticException: / by zero
at shiyizhang.Demo1.main(Demo1.java:7)
1.1异常处理流程
-
上述代码会抛出异常,原因是0不能作为除数
-
当程序运行前或者运行期间发生了异常,那么JVM如何处理异常呢?
(1)Java对运行前和运行期间可能发生的异常进行了预定义,Java定义了很多与异常相关的类,这些类 都是以Exception结尾的,每个异常类来表示一个特定的异常,比如算术异常用ArithmeticException类来 表示,用NullPointerExcetion表示空指针异常。
(2)当异常发生时,此时JVM就会自动创建异常类的对象,JVM会将这个异常对象用throw语句将异常对象抛出,抛出的目的是让开发者知道程序发生了异常,开发者重新修改代码,使得代码正确运行。
-
当程序发生异常时,程序就终止运行了。
异常处理是为了消除程序中的异常,保证程序中没有异常,进而保证程序能够继续运行。
2、Java异常体系结构
(1)Error类:表示仅靠程序本身无法恢复的严重错误,如内存溢出、动态链接失败、虚拟机错误。
(2)Exception类:由java应用程序抛出和处理的非严重错误,如所需文件找不到、算数运算出错等。Exception可分为两大类:
运行时异常:也叫unchecked异常,包括RuntimeException及其子类。不要求程序必须处理它们。
设计时异常:也叫checked异常:除了运行时异常外的其他从Exception类继承的异常类。
常见的异常类:
异常类名 | 异常分类 | 说明 |
Exception | 设计时异常 | 异常层次结构的根类 |
IOExceptin | 设计时异常 | IO异常的根类,属于非运行时异常 |
FileNotFoundException | 设计时异常 | 文件操作时,找不到文件。属于非运行时异常。 |
RuntimeException | 运行时异常 | 运行时异常的根类,RuntimeException及其子类,不要求必须处理 |
ArithmeticException | 运行时异常 | 算数运算异常,比如:除数为零 |
IllegalArgumentException | 运行时异常 | 方法接收到非法参数,属于运行时异常 |
ArrayIndexOutOfBoundsException | 运行时异常 | 数组越界访问异常,属于运行时异常 |
NullPointerException | 运行时异常 | 尝试访问null对象的成员时发生的空指针异常,属于运行时异常 |
ArrayStoreException | 运行时异常 | 数据存储异常,写数组操作时,对象或数据类型不兼容 |
ClassCastException | 运行时异常 | 类型转换异常 |
IllegalThreadStateException | 运行时异常 | 试图非法改变线程状态,例如试图启动一已经允许的线程 |
NumnerFormatException | 运行时异常 | 数据格式异常,试图把一字符串非法转换成数值 |
2.1 错误与异常的区别
错误是Error(JVM错误,内存溢出、虚拟机错误等)
异常是Exception
错误无法通过代码编写解决问题,Exception可以通过try-catch-finally或者通过throw,trows解决。
3、Java异常处理机制
处理异常的两种办法:
使用try-catch-finally
使用throws-throw
3.1 使用try-catch处理异常
示例2:
运行结果:
begin
catched
java.lang.ArithmeticException: / by zero
over
at shiyizhang.Demo2.mm(Demo2.java:10)
at shiyizhang.Demo2.main(Demo2.java:4)
分析:
1、try块中存放可能发生异常的代码
2、catch块存放处理异常的代码
3、当try块中发生异常时,程序立即跳转到catch块运行,catch块的作用是捕获异常,当异常被捕获以后,异常就没有了,所以程序就可以继续运行了。
4、如果try块中没有发生异常,那么程序就不会进入catch块。
catch语句块中可以加入用户自定义处理信息,也可调用异常对象的方法输出异常信息,常用方法如下:
printStackTrace():输出异常堆栈信息,该方法打印出的跟踪信息可以分析方法的调用过程,错误一定是发生在从上到下寻找到的第一个自定义的类。
getMessage():返回异常信息描述字符串,描述异常产生的原因。
3.2 使用try-catch-finally处理异常
无论try快中是否发生异常,finally语句块中的代码总能执行。finally的作用是用于回收系统资源,比如释放数据库连接,断开网络等。
示例3:
运行结果:
begin
catched
java.lang.ArithmeticException: / by zero
finally
over
at shiyizhang.Demo3.main(Demo3.java:8)
3.3 使用多重catch处理异常
一段代码可能回引发多种类型的异常,这时可以在一个try语句块之后加多个catch语句块处理不同的异常。但是排列顺序必须是从子类到父类,最后一个一般都是Exception类。因为如果父类在前,那么后面catch语句块将不会被执行。
示例4:
运行结果:
begin
java.lang.ArithmeticException: / by zero
错误原因:/ by zero
catched
finally
over
at shiyizhang.Demo4.main(Demo4.java:10)
3.4 使用throws和throw抛出异常
如果程序本身没有错误,但是数据不符合业务要求,此时开发人员可以自己抛出异常对象。此时应该使用throws和throw配合实现抛出异常。
示例5:
class Person{
private String name; //姓名
private int age =0;
private String gender ="男"; //性别
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender)throws Exception{
if ("男".equals(gender) ||"女".equals(gender)) {
this.gender =gender;
}else {
throw new Exception("性别必须是男或女");
}
}
public void print() {
System.out.println("姓名:"+this.getName()+",性别:"+getGender()+",年龄"+getAge());
}
}
public class Demo5 {
public static void main(String[] args) {
Person person =new Person();
try {
person.setName("钟小馗");
person.setAge(10);
person.setGender("nv");
person.print();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
java.lang.Exception: 性别必须是男或女
at shiyizhang.Person.setGender(Demo5.java:27)
at shiyizhang.Demo5.main(Demo5.java:40)
3.4.1 throws和throw的区别
(1)throw用于程序员自行抛出异常,throws用于声明该方法内抛出异常。
(2)throw必须用在方法内部,表示抛出异常,可以作为单独语句使用;throws必须用在方法声明的后面,不能单独使用。它表示告诉调用者,该方法可能发生什么样的异常,而主调方法需要处理这个异常。在被调方法中使用throw和throws,而在主调方法中使用try-catch捕获异常。
(3)throw抛出一个异常对象,只能是一个;throws后面跟异常类,可以跟多个。
特殊情况:
示例6:
public class Demo6 {
public static void main(String[] args) throws ArithmeticException {
int i=1, j = 0;
System.out.println("begin");
int result = i/j;
System.out.println("end");
}
}
异常抛给JVM了,由JVM处理异常。
3.5 自定义异常
当jdk中的异常类不能满足需求时,可以自定义异常类。
示例7:
class GenderException extends Exception{
public GenderException(String gender) {
super(gender);
}
}
class Person{
private String name; //姓名
private int age =0;
private String gender ="男"; //性别
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender)throws GenderException{
if ("男".equals(gender) ||"女".equals(gender)) {
this.gender =gender;
}else {
throw new GenderException("性别必须是男或女");
}
}
public void print() {
System.out.println("姓名:"+this.getName()+",性别:"+getGender()+",年龄"+getAge());
}
}
public class Demo7 {
public static void main(String[] args) {
Person person =new Person();
try {
person.setName("钟小馗");
person.setAge(10);
person.setGender("nv");
person.print();
} catch (Exception e) {
e.printStackTrace();
System.out.println("异常原因是:"+e.getMessage());
}
}
}
运行结果:
异常原因是:性别必须是男或女
java.lang.Exception: 性别必须是男或女
at shiyizhang.Person.setGender(Demo5.java:27)
at shiyizhang.Demo7.main(Demo7.java:10)
3.6 异常链
在处理异常时,有时候会出现A方法调用B方法,B方法抛出了异常,A方法会继续抛出这个异常。