Java异常复习
异常
异常:异常就是代表程序出现的问题
学习异常的目的就是学会程序出了异常之后,该如何处理

Error:表示系统级别的错误(属于严重问题)
Exception:叫做异常,代表程序可能出现的问题。我们通常会用 Exception 以及他的子类来封装程序出现的问题
运行时异常:RuntimeException 及其子类,编译阶段不会出现异常提醒。运行时出现的异常(如:数组索引越界异常 ArrayIndexOutOfBoundsException)
编译时异常:编译阶段就会出现异常提醒的。(如:日期解析异常 ParseException)
package com.faxont.exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo1 {
public static void main(String[] args) throws ParseException {
// 编译时异常(在编译阶段,必须要手动处理,否则代码报错)
String time = "2030年1月1日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date date = sdf.parse(time);
System.out.println(date);
// 运行时异常(在编译阶段是不需要处理的,是代码运行时出现的异常)
int[] arr = {1, 2, 3};
System.out.println(arr[3]);// ArrayIndexOutOfBoundsException
}
}

编译时异常在于提醒程序员检查本地信息;而运行时异常是代码出错而导致程序出现的问题。
异常的作用
作用一:异常是用来查询 bug 的关键参考信息
作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
异常的处理方式
JVM 默认的处理方式
- 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
- 程序停止执行,下面的代码不会再执行了
自己处理
捕获异常
// 格式
try {
可能出现异常的代码;
} catch(异常类名 变量名) {
异常的处理代码;
}
目的:当代码出现异常时,可以让程序继续往下执行。
package com.faxont.exception;
public class ExceptionDemo2 {
public static void main(String[] args) {
/*
自己处理(捕获异常)
格式:
try {
可能出现异常的代码;
} catch (异常类名 变量名) {
异常的处理代码;
}
*/
int[] arr = {1, 2, 3, 4, 5, 6};
try{
// 可能出现的异常的代码
/**
* 此处出现了异常,程序就会在这里创建一个 ArrayIndexOutOfBoundsException 异常对象
* new ArrayIndexOutOfBoundsException();
* 拿着这个对象到 catch 的小括号中对比,看括号中的变量是否可以接收这个对象
* 如果能被接收,就表示该异常被捕获,执行 catch 里面对应的代码
* 当 catch 里面所有的代码执行完毕,继续执行 try ... catch 体系下面的其它代码
*/
System.out.println(arr[10]);
}catch(ArrayIndexOutOfBoundsException e){
// 如果出现了 ArrayIndexOutOfBoundsException 异常,就执行这个 catch 中的代码
System.out.println("数组越界异常");
}
System.out.println("程序继续执行");
}
}
灵魂四问
- 如果 try 中没有遇到问题,怎么执行?
会把 try 里面所有的代码全部执行完毕,不会执行 catch 里面的代码。
- 如果 try 中可能会遇到多个问题,怎么执行?
解决:会写多个 catch 与之对应。
如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面。
在 JDK7 之后,我们可以在 catch 中同时捕获多个异常,中间用 | 隔开;
表示如果出现了 A 异常或者 B 异常的话,采取同一处理。
- 如果 try 中遇到的问题没有被捕获,怎么执行?
相当于 try ... catch 的代码白写了,最终还是会交给虚拟机进行处理。
- 如果 try 中遇到了问题,那么 try 下面的其它代码还会执行吗?
下面的代码就不会执行了,直接跳转到对应的 catch 当中,执行 catch 里面的语句体;
但是如果没有对应的 catch 与之匹配,那么还是会交给虚拟机进行处理。
抛出异常
throws
注意:写在方法定义处,表示声明一个异常,告诉调用者,使用本方法可能会有哪些异常
public void 方法() throws 异常类名1, 异常类名2 ...{
...
}
- 编译时异常:必须要写。
- 运行时异常:可以不写。
throw
注意:写在方法内,结束方法,手动抛出异常对象,交给调用者,方法中下面的代码不再执行了
public void 方法(){
throw new NullPointerException();
}
package com.faxont.exception;
public class ExceptionDemo4 {
public static void main(String[] args) {
/*
throws : 写在方法定义处,表示声明一个异常,告诉调用者,使用本方法可能会有哪些异常
throw : 写在方法内,结束方法,手动抛出异常对象,交给调用者,方法中下面的代码不再执行了
需求:
定义一个方法求数组的最大值
*/
int[] arr = {1, 2, 3, 4, 5};
int[] arrNull = null;
int[] arrEmpty = new int[0];
System.out.println(getMax(arr));
try {
System.out.println(getMax(arrNull));
} catch (NullPointerException e) {
System.err.println("空指针异常");
}
try {
System.out.println(getMax(arrEmpty));
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("数组索引越界异常");
}
}
// NullPointerException 和 ArrayIndexOutOfBoundsException 都是运行时异常,即 RuntimeException 的子类,运行时异常可以省略不写
public static int getMax(int[] arr) /*throws NullPointerException, ArrayIndexOutOfBoundsException*/{
if(arr == null){
// 手动创建一个异常对象,并把这个异常交给方法的调用者处理
// 此时方法就会结束,下面的代码不会再执行了
throw new NullPointerException("数组不能为null");
}
if(arr.length == 0){
// 手动创建一个异常对象,并把这个异常交给方法的调用者处理
// 此时方法就会结束,下面的代码不会再执行了
throw new ArrayIndexOutOfBoundsException("数组不能为空");
}
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
}
return max;
}
}
Throwable 的成员方法
| 方法名称 | 说明 |
|---|---|
| public String getMessage() | 返回此 throwable 的详细消息字符串 |
| public String toString() | 返回此可抛出的简短描述 |
| public void printStackTrace() | 把异常的错误信息输出在控制台 |
package com.faxont.exception;
public class ExceptionDemo3 {
public static void main(String[] args) {
/*
public String getMessage() 返回此 throwable 的详细消息字符串
public String toString() 返回此可抛出的简短描述
public void printStackTrace() 把异常的错误信息输出在控制台(仅仅是打印信息,不会停止程序运行)
*/
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
System.out.println(e.toString());
e.printStackTrace();// 最常用的,因为其所包含的信息是最多的
}
System.out.println("程序继续执行...");
// 正确的输出语句
System.out.println("123");
// 错误的输出语句(输出错误信息的输出语句)
// 打印出来的顺序不是固定的,有可能跟代码顺序不一样
System.err.println("123");// 输出的字符是红色的,跟平时看到的错误信息是一样的
}
}
练习:键盘录入数据
需求:
键盘录入自己的姓名和年龄
姓名的长度在 3 ~ 10 之间
年龄的范围为 18 ~ 40 岁,
超出这个范围视为异常数据,不能赋值需要重新录入,直到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了 abc 等情况
package com.faxont.exception;
import java.util.InputMismatchException;
import java.util.Scanner;
public class ExceptionDemo5 {
public static void main(String[] args) {
/*
需求:
键盘录入自己的姓名和年龄
姓名的长度在 3 ~ 10 之间
年龄的范围为 18 ~ 40 岁,
超出这个范围视为异常数据,不能赋值需要重新录入,直到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了 abc 等情况
*/
// 创建 Scanner 对象
Scanner sc = new Scanner(System.in);
// 创建 Person 对象
Person p = new Person();
while (true) {
try {
// 录入姓名
System.out.println("请输入自己的姓名:");
String name = sc.next();
p.setName(name);
// 录入年龄
System.out.println("请输入自己的年龄:");
int age = sc.nextInt();
p.setAge(age);
// 全部正确,录入成功,打印出录入结果
System.out.println("录入成功!" + p);
break;
} catch (InputMismatchException e){
System.out.println("请输入数字!");
sc.next();// 输入错误,需要清空输入缓冲区
} catch (RuntimeException e) {
// 捕获自定义异常信息
e.printStackTrace();
}
}
}
}
package com.faxont.exception;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
// 验证姓名长度是否符合规范
if (name.length() < 3 || name.length() > 10) {
throw new NameFormatException("姓名长度必须在 3 ~ 10 之间,请重新输入!");
}
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
// 验证年龄是否符合规范
if (age < 18 || age > 40) {
throw new AgeOutOfException("年龄范围必须在 18 ~ 40 岁之间,请重新输入!");
}
this.age = age;
}
public String toString() {
return "姓名:" + name + ", 年龄:" + age;
}
}
自定义异常
意义:就是为了让控制台的报错信息更加的清晰
-
定义异常类
-
写继承关系
-
空参构造
-
带参构造
package com.faxont.exception;
public class NameFormatException extends RuntimeException{
// 技巧:
// NameFormat:当前异常的名字,表示姓名格式化问题
// Exception:表示当前类是一个异常类
// 运行时:RuntimeException 核心 就表示由于参数错误而导致的问题
// 编译时:Exception 核心 提醒程序员检查本地信息
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
package com.faxont.exception;
public class AgeOutOfException extends RuntimeException{
public AgeOutOfException() {
}
public AgeOutOfException(String message) {
super(message);
}
}

浙公网安备 33010602011771号