Java中的异常详解
前言
生活中的异常:
- 每天上班坐公交车去,正常的话半个小时,但是有时候会出现堵车(一定会出现的),或者遇到交通事故等,就有可能造成上班迟到的情况,这就是一种异常情况。
- 睡觉的时候,睡的正香,突然一个电话过来,被吵醒了。
- 在大街上走着,突然被绊倒了。
概述
Java中的异常:
- 异常是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序。简单来说就是程序出现了不正常的情况。
- 异常本质就是Java当中对可能出现的问题进行描述的一种对象体现。
常见异常:
- 除数不能为0异常(ArithmeticException)
- 空指针异常(NullPointException)
- 数组越界异常(ArrayIndexOutOfBoundsException)
- 类型转换异常(ClassCastException)
Throwable类
Throwable 类是 Java 语言中所有错误或异常的超类。
成员方法:
- public String getMessage():返回此 throwable 的详细消息字符串
- public String toString():获取异常类名和异常信息。
- public void printStackTrace():获取异常类名和异常信息,以及异常出现在程序的位置。
- public void printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。
Error和Exception
-
Error:称为错误,由Java虚拟机生成并抛出,程序对其不做处理。
-
Exception:所有异常类的父类,其子类对应了各种各样可能出现的异常事件,一般需要用户显示的声明或捕获。
Exception类
所有异常类的父类,其子类对应了各种各样可能出现的异常事件,一般需要用户显示的声明或捕获。
运行时期异常(RuntimeException):
- 运行时期异常,又称为非受检异常,RuntimeException及其所有子类都是运行时期异常。
编译时期异常:
- 不是继承自RuntimeException的Exception的子类都成为编译时期异常
异常处理
如果我们不做任何处理,异常将会交由虚拟机来处理。
虚拟机的处理方式:
- 把异常的名称,异常出现的位置,异常原因,等信息输出打印在控制台,并同时将程序停止执行。
思考:
在实际开发当中显然直接将应用程序挂掉的这种方式是不可取的,就算程序有异常,我们也理应让程序继续执行下去,提高用户体验。那我们又该怎么做呢?
分析
异常的执行流程:
-
程序执行到错误行,系统会创建一个异常对象,并且抛给我们
ArithmeticException exp = new ArithmeticException("/by zero");
throw exp;
-
程序进入catch块进行逐个匹配,匹配成功,程序执行catch块代码
ArithmeticException ae = exp;
Exception e = exp;
-
匹配失败,交给jvm处理
jvm默认是如何处理异常的?
-
打印错误信息
a.异常名称 java.lang.ArithmeticException
b.异常的消息 / by zero
c.异常所发生的方法位置 at com.sxt.exceptiondemo.ExceptionDemo02.main
d.异常所在Java文件中 ExceptionDemo02.java
e.异常发生行号 14
-
终止程序
System.exit(0);
处理异常的标准方式:
- 能够显示处理的尽量显示处理,提高程序的可读性。
- 但是一定要在异常处理的最后加上 父类Exception处理。
处理方式
- try...catch...finally
- throws抛出异常
-
try...catch...finally
-
try...catch...finally的处理格式:
异常处理的格式:
try{
//放置程序可能出现问题的代码
}catch(异常类 异常名){
//这里放置异常处理的代码
} finally{
//释放资源
} -
多个异常的处理
格式:try{
...
}catch(异常类名 变量名) {
...
}catch(异常类名 变量名) {
...
} catch...排列catch 语句的顺序:
- 先子类后父类
- 发生异常时按顺序逐个匹配
- 只执行第一个与异常类型匹配的catch语句
-
Throws和Throw
throws关键字
- 概述:在定义一个方法的时候可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而交给方法的调用者进行处理。
- 格式: [修饰符] 返回值类型 方法名(参数列表) [throws 异常类1,异常类2....]{
}
注意:
1、如果一个方法声明的是编译时期异常,则在调用这个方法之处必须处置这个异常(谁调用谁处理)。
2、重写一个方法时,它所声明的异常范围不能被扩大
public static int calc() throws ArithmeticException{
int a = 10;
int b = 0;
int result = a/b;
return result;
}
throw关键字
- 在方法代码中主动抛出一个异常。如果方法代码中自行抛出的异常是编译时期异常,则这个方法要用throw关键字声明这个异常。
public static void method2() throws ArithmeticException {
int a = 10;
int b = 0;
if (b == 0) {
// throw
throw new ArithmeticException("除数为0了!");
}
System.out.println(a/b);
}
throws和throw的区别
- throws用在方法声明后面,跟的是异常类名,throw用在方法体内,跟的是异常对象名。
- throws可以跟多个异常类名,用逗号隔开,throw只能抛出一个异常对象名。
- throws表示抛出异常,由该方法的调用者来处理,throw表示抛出异常,由方法体内的语句处理。
- throws表示出现异常的一种可能性,并不一定会发生这些异常,throw则是抛出了异常,执行throw则一定抛出了某种异常。
finally关键字
finally修饰的代码块一定会被执行,除非在执行到finally之前程序异常退出或者调用了系统退出的方法。
finally用于释放资源,在IO流操作和数据库操作中会见到。
注意:
finally碰到return时finally一定会执行,那执行顺序?
public class ExceptionDemo09 {
public static void main(String[] args) {
System.out.println(test()); // 4 3
}
public static int test() {
int x = 1;
try {
System.out.println(x++ / 0); // 2
} catch (Exception e) {
x++; //
return x; // return 3;
} finally {
++x; // 4
System.out.println(x); // 4
}
return x;
}
}
分析:
在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。
在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果。
因此,即使finally中对变量x进行了改变,但是不会影响返回结果。它应该使用栈保存返回值。
自定义异常
在工作中有许多异常需要自己写。那如何写一个异常呢?
- 编写一个分数必须在0-100分之间的异常,并且使用这个异常。
步骤:
-
定义一个异常继承Throwable或者Exception或者RuntimeException
-
编写构造方法
-
带参
-
无参
-
public class ExceptionDemo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入一个分数:");
double score = input.nextDouble();
Teacher teacher = new Teacher();
try {
System.out.println(teacher.isBetween0To100(score) ? "分数合法" : "分数不合法");
} catch (ScoreException e) {
// e.printStackTrace();
System.err.println(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
} finally {
input.close();
}
System.out.println("分数批改完毕!");
}
}
class ScoreException extends Exception{
public ScoreException(){}
public ScoreException(String message) {
super(message);
}
}
class Teacher{
public boolean isBetween0To100(double score) throws ScoreException{
if (score > 100 || score < 0) {
throw new ScoreException("分数必须在0-100分之间!!!");
}
return true;
}
}
以上
@Fzxey