异常的理解与使用
异常:就是程序出现了不正常的情况,程序在执行过程中,数据导致程序不正常,最终会导致JVM的非正常停止
异常体系-Throwable
-
Throwable
-
Error:严重问题,通过代码无法处理,比如:内存溢出
-
Exception:称为异常类,它表示程序本身可以处理的问题
- RuntimeException及其子类:运行时异常。(空指针异常,数组索引越界异常)
- 非RuntimeException及其子类:编译时异常,编译期必须处理的,否则程序不能通过编译。(日期格式化异常)
-
虚拟机处理异常的方式
- JVM的默认处理方案
- 如果程序出了问题,我们没有做任何处理,最终JVM会默认的处理
- 把异常的类型,原因,位置打印在控制台
- 程序停止执行
- 注意:程序中出现了异常,会在当前位置创建此异常的对象,对象中包含了异常的信息,并把此异常交给本方法的调用者处理
- 如果程序出了问题,我们没有做任何处理,最终JVM会默认的处理
手动处理异常的方式
声明:throws
-
遇到异常发生了,自己不处理,交给别人来处理
-
最终还是需要有一个位置使用try…chach来处理异常
-
结论:在main方法中,只能使用try…chach
// 使用声明的方式处理异常,声明是书写在方法定义上
public void method(String name) throws NullPointerException, ArrayIndexOutOfBoundsException{
// ...
}
-
作用:
-
表示告知调用者当前的方法可能会出现某些异常,使用时需要注意
-
如果当前方法没有出现任何异常,那么代码会正常执行
-
如果当前方法中出现了异常,会把异常交给本方法调用者处理(甩锅)
-
-
练习:定义两个方法一个运行时期异常,一个声明编译时期异常!
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo2 {
public static void main(String[] args) {
try {
fun1(null);
} catch (NullPointerException e) {
System.out.println("空指针异常");
}
try {
fun2();
} catch (ParseException e) {
System.out.println("日期格式错误");
}
}
// 运行时异常
public static void fun1(String name) {
System.out.println(name.length());
}
// 编译时异常
public static void fun2() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2022/11/11 11:11:11");
String time = sdf.format(date);
System.out.println(time);
}
}
// 编译时异常因为在编译时就会检查,所以必须要写在方法后面进行显示声明
// 运行时异常因为在运行时才会发生,所以在方法后面可以不写
// 如果声明多个异常有子父类关系,那么只要声明一个父类即可(多态)
-
throws和throw的区别
- throws:
- 用在方法声明后面,跟的是异常类名
- 表示声明异常,调用该方法有可能会出现这样的异常
- 异常对象有JVM创建
- throw:
- 用在方法体内,跟的是异常对象
- 表示手动抛出异常对象,告知调用者数据传入有误
- 异常对象我们自己创建
- throws:
捕获:try…catch
-
遇到异常发生了,自己处理
-
捕获异常格式
try{ // 可能出错的代码 } catch(异常对象) { // 出现异常的处理方式 }
-
捕获异常代码实践
定义一个方法接受一个生日日期字符串(xxxx年xx月xx),main方法中让用户输入一个生日日期字符串,调用设计好的方法计算在地球上活了多少天。
要求:如果解析发生异常,捕获异常,提示用户要重新输入生日日期字符串,直到输入正确的日期为止。
思考:设计此代码的过程中想想什么时候捕获异常,什么时候声明异常?
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
/*定义一个方法接受一个生日日期字符串(xxxx年xx月xx),main方法中让用户输入一个生日日期字符串,调用设计好的方法计算在地球上活了多少天。
要求:如果解析发生异常,捕获异常,提示用户要重新输入生日日期字符串,直到输入正确的日期为止。
思考:设计此代码的过程中想想什么时候捕获异常,什么时候声明异常?*/
public class Demo1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的生日:");
while (true) {
String dateStr = sc.nextLine();
try {
long day = life(dateStr);
System.out.println("您在地球已经活了" + day + "天。");
break;
} catch (ParseException e) {
System.out.println("日期格式错误,请重新输入生日:(xxxx年xx月xx)");
}
}
}
public static long life(String dateStr) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd");
Date birthDate = sdf.parse(dateStr);
long birthTime = birthDate.getTime();
Date now = new Date();
long nowTime = now.getTime();
long time = nowTime - birthTime;
return time / 1000 / 60 / 60 / 24;
}
}
异常处理的选择
-
自定义方法(程序员自己写的方法),通常都可以使用:声明
- 方法内代码比较清爽(阅读性好)
- 把异常统一抛出到main方法中,进行统一的处理
-
捕获的使用场景:
- main方法中只能使用捕获
- 当前方法中没有throws
Throwable的成员方法
方法名 | 说明 |
---|---|
public String getMessage() | 返回此throwable的详细消息字符串 |
public String toString() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
自定义异常
-
程序员自己编写的异常类
-
解决问题:JDK提供的异常类在命名上做不到见名知意
-
使用:
public 自定义异常类 extends Exception{ public 自定义异常类(){ // 当前自定义异常类为:编译时异常 // super(); } public 自定义异常类(String message){ super(message); } } public 自定义异常类 extends RuntimeException{// 当前自定义异常类为:运行时异常 }
-
注意:
- 如果要自定义编译时异常,就继承Exception
- 如果要自定义运行时异常,就继承RuntimeException