异常
- 1 异常概述
- 2 异常处理方式
- 2.1 JVM默认处理异常的方式
- 2.2 throws方式处理异常
- 2.3 throw抛出异常
- 2.4 try-catch方式处理异常
- 2.5 Throwable成员方法
- 2.6 异常的练习
- 3 自定义异常
1 异常概述
异常:就是程序出现了不正常的情况。程序在执行的过程中,出现的非正常的情况,最终会导致JVM的正常终止。
注意:
- 语言错误不属于异常体系
编译时异常和运行时异常的区别
- 编译时异常
- 都是Exception类及其子类
- 必须显示处理,否则程序就会发生错误,无法通过编译
- 运行时异常
- 都是RuntimeException类及其子类
- 无需显示处理,也可以和编译时异常一样处理
2 异常处理方式
2.1 JVM默认处理异常的方式
public static void main(String[] args){
//思考:控制台为什么会有这样的红色字体呢? 是谁打印的?
int [] arr = {1,2,3,4,5};
System.out.println(arr[10]);
//当代码出现了异常,那么就在这里创建了一个异常对象,new ArrayIndexOutOfBoundsException();
//首先会看,程序中有没有自己处理异常的代码;
//如果没有,交给本方法的调用者处理;
//最终这个异常会交给虚拟机默认处理。
System.out.println("嘿嘿嘿");
如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤:
- 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
- 程序停止执行(哪里出现了异常,那么程序就在哪里停止, 下面的代码不执行了)
2.2 throws方式处理异常
定义格式:
public void 方法() throws 异常类名 {
}
示例代码:
public static void main(String[] args) throws ParseException {
method1(); // 此时调用者也没有处理,还是会交给虚拟机处理.
method2(); // 还是继续交给调用者处理,而main方法的调用者是虚拟机还是会采取虚拟机默认处理异常的方法。
}
// 运行时异常
private static void method1() /*throws NullPointerException*/ {
int [] arr = null;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
// 编译时异常
private static void method2() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
sdf.parse("2048-10月10日");
}
注意:
- 编译时异常因为在编译时就会检查,所以必须要写在方法后面进行显示声明,将来谁调用这个方法谁处理。两种处理方案:try…catch… 或者 throws
- 运行时异常因为在运行时才会发生,所以在方法后面可以不写,运行时出现异常默认交给 jvm 处理
2.3 throw抛出异常
思考:以前出现了异常,虚拟机帮我们创建一个异常对象,抛给调用者。但是如果我们需要自己手动创建一个异常对象该如何写?
throw new 异常();
注意:
- 这个格式是在方法内的,表示当前代码手动抛出一个异常,下面的代码不用再执行了
throws和throw的区别:
public static void main(String[] args) {
// int [] arr = {1,2,3,4,5};
int [] arr = null;
printArr(arr);// 就会 接收到一个异常
// 我们还需要自己处理一下异常
}
private static void printArr(int[] arr) {
if(arr == null){
// 调用者知道成功打印了吗?
// System.out.println("参数不能为null");
throw new NullPointerException(); // 当参数为null的时候
// 手动创建了一个异常对象,抛给了调用者
}else{
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
2.4 try-catch方式处理异常
定义格式:
try {
可能出现异常的代码;
} catch(异常类名 变量名) {
异常的处理代码;
}
执行流程:
- 程序从 try 里面的代码开始执行
- 出现异常,就会跳转到对应的 catch 里面去执行
- 执行完毕之后,程序还可以继续往下执行
try-catch方式处理异常的好处:
- 可以让程序继续往下执行
示例代码:
public static void main(String[] args) {
int [] arr = null;
try{
// 有可能发现异常的代码
printArr(arr);
}catch (NullPointerException e){
// 如果出现了这样的异常,那么我们进行的操作
System.out.println("参数不能为null");
}
System.out.println("嘿嘿嘿"); // 可以执行到
}
private static void printArr(int[] arr) {
if(arr == null){
throw new NullPointerException();
}else{
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
注意:
- 如果 try 中没有遇到问题,怎么执行?
- 会把 try 中所有的代码全部执行完毕,不会执行 catch 里面的代码
- 如果 try 中遇到了问题,那么 try 下面的代码还会执行吗?
- 那么直接跳转到对应的 catch 语句中,try 下面的代码就不会再执行了 。当catch里面的语句全部执行完毕,表示整个体系全部执行完全,继续执行下面的代码
- 如果出现的问题没有被捕获,那么程序如何运行?
- 那么 try…catch 就相当于没有写,那么也就是自己没有处理,默认交给虚拟机处理
- 同时有可能出现多个异常怎么处理?
- 出现多个异常,那么就写多个catch就可以了。还要特别注意如果多个异常之间存在子父类关系,那么父类一定要写在下面
2.5 Throwable成员方法
常用方法:
示例代码:
public static void main(String[] args) {
try {
int [] arr = {1,2,3,4,5};
System.out.println(arr[10]);//虚拟机帮我们创建了一个异常对象 new ArrayIndexOutOfBoundsException();
} catch (ArrayIndexOutOfBoundsException e) {
/*String message = e.getMessage();
System.out.println(message);*/
/* String s = e.toString();
System.out.println(s);*/
e.printStackTrace(); // 输出红色的异常信息
}
System.out.println("嘿嘿嘿"); // 可以输出
}
2.6 异常的练习
-
需求
键盘录入学生的姓名和年龄,其中年龄为18 - 25岁,超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止
-
实现步骤
- 创建学生对象
- 键盘录入姓名和年龄,并赋值给学生对象
- 如果是非法数据就再次录入
Student 类
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age >= 18 && age <= 25){
this.age = age;
}else{
//当年龄不合法时,产生一个异常
throw new RuntimeException("年龄超出了范围");
}
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
public class ExceptionDemo{
public static void main(String[] args) {
// 键盘录入学生的姓名和年龄,其中年龄为 18 - 25岁,
// 超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止。
Student s = new Student();
Scanner sc = new Scanner(System.in);
System.out.println("请输入姓名");
String name = sc.nextLine();
s.setName(name);
while(true){
System.out.println("请输入年龄");
String ageStr = sc.nextLine();
try {
int age = Integer.parseInt(ageStr);
s.setAge(age);
break;
} catch (NumberFormatException e) {
System.out.println("请输入一个整数");
continue;
} catch (AgeOutOfBoundsException e) {
System.out.println(e.toString());
System.out.println("请输入一个符合范围的年龄");
continue;
}
}
System.out.println(s);
}
}
3 自定义异常
-
自定义异常
当Java中提供的异常不能满足我们的需求时,我们可以自定义异常
-
实现步骤
- 定义异常类
- 写继承关系
- 提供空参构造
- 提供带参构造
异常类:
public class AgeOutOfBoundsException extends RuntimeException {
// 可以通过快捷键alt+insert自动生成
public AgeOutOfBoundsException() {
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
Student类中做如下修改:
public void setAge(int age) {
if(age >= 18 && age <= 25){
this.age = age;
}else{
//如果Java中提供的异常不能满足我们的需求,我们可以使用自定义的异常
throw new AgeOutOfBoundsException("年龄超出了范围");
}
}
测试类中做如下修改:
catch (AgeOutOfBoundsException e) {
System.out.println(e.toString());
System.out.println("请输入一个符合范围的年龄");
continue;
}