概念:异常就是程序出现的问题
同时我们应该明白,我们学习异常并不是为了让我们以后写的程序不出异常,而是让我们能够做到程序出现了异常后我们直到这个异常应该怎么去处理
一.异常举例
Error:
代表的系统级别错误,系统一旦出现问题,负责该系统的公司会将这些错误封装成Error对象,换句话说,Error是该公司内部处理的,不是交给我们处理的,因此我们开发人员不需理会Error
Exception:
异常,代表程序可能出现的问题,我们通常会用Exception以及它的子类来封装程序出现的问题
运行时异常:RuntimeException及其子类,在编译阶段不会出现异常提醒,而是会在运行时出现异常提醒
编译时异常:编译阶段就出现异常提醒
编译时异常和运行时异常的区别:
编译时异常除了RuntimeException和他的子类,其他都是编译时异常,编译阶段需要进行处理,作用在于提醒程序员
运行时异常是RuntimeException本身和其所有子类都是运行时异常,编译阶段不报错,是程序运行时出现的,且一般是由于参数传递错误带来的问题
二.异常的作用
1.异常可以用来查询bug的关键参考信息
例:查看Student数组中元素的信息
public class Exception {
public static void main(String[] args) {
Student[] stu = new Student[3];
System.out.println(stu[0].getName());
}
}
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) {
this.age = age;
}
}
这一段代码最后的报错信息是这样的:
它显示了错误在代码的第几行,以及错误的原因是什么,上方的代码明显是因为没有在Student数组中添加具体的数据,stu[0]中的数据为null(空),所以报错
2.异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
三.异常的处理方式
1.JVM默认的处理方式
(1).把异常的名称,异常原因及异常出现的位置等信息输出在控制台
(2).程序停止执行,下面的代码不会再执行
2.自己处理(捕获异常)
格式:
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
目的:当代码出现异常时,跳过这个异常让程序继续往下执行
public class Exception {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("OUt OF BOUNDS");
}
System.out.println("RUN?");
}
}
出现了索引越界异常,但我们将其进行了输出语句的处理,并不是使用的JVM默认的处理方式,程序也没有在出现索引越界异常时终止,而是继续将整个程序运行完成
捕获异常时的问题:
(1).如果try中没有遇到问题,怎么执行?
最终程序会把try中的所有代码执行完毕,不会执行catch中的代码
(2).如果try中可能会遇到多个问题,怎么执行?
需要写多个catch与可能会遇到的问题一一对应,只要try中包含有这个问题,那么try中的代码就会执行,如果try中的问题我们没有写对应的catch,那么它既不会报错也不会执行
注意1:如果这些异常中存在父子关系的话,父类一定要写在子类下面(是异常的父子关系,不是上方可能出现问题的代码的父子关系!!!如Exception是ArrayIndexOutOfBoundsException的父类)
注意2:在JDK7以后我们可以在同一个catch中捕获多个异常(即对多个不同的异常采用同一种处理方式),格式为:
//只有一个|
catch(ArrayIndexOutOfBoundsException | ArithmaticException)
(3).如果try中遇到的问题没有被捕获,怎么执行?
那么就会使用JVM默认的处理方式,即:
(1).把异常的名称,异常原因及异常出现的位置等信息输出在控制台
(2).程序停止执行,下面的代码不会再执行
(4).如果try中遇到了问题,那么try下面的其他代码还会执行吗?
下面的代码不会执行,直接跳转到对应的catch当中,执行catch里面的语句体
但是如果没有对应的catch与其匹配,那么还是会交给JVM进行处理
四.异常中的常见方法
public String getMessage() 返回此throwable的详细消息字符串
public class Exception {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
String message = e.getMessage();
System.out.println(message);
}
System.out.println("RUN?");
}
}
public String toString()返回此可抛出的简短描述
public class Exception {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
String message = e.toString();
System.out.println(message);
}
System.out.println("RUN?");
}
}
public void printStackTrace()把异常的错误信息输出在控制台
public class Exception {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
System.out.println("RUN?");
}
}
五.抛出异常
1.throws
写在方法定义处,表示声明一个异常,告诉调用者,使用本方法可能会有哪些异常
格式:
public void method()throws Exception's name1,Exception's name2...{
}
注意点1:编译时异常:必须要写
注意点2:运行时异常:可以不写
2.throw
格式:
public void method(){
throw new NUllPointerException();
}
写在方法内,结束方法,手动抛出异常对象,交给调用者,方法中下面的代码就不再执行了
六.异常的综合练习
键盘录入数据
需求:
1.键盘录入女朋友的姓名和年龄
2.姓名的长度在3-10之间
3.年龄的范围为18-40岁
超出这个范围的异常数据不能正确地给其赋值,需要重新录入,一直到正确为止
提示:需要考虑用户在键盘录入时的所有情况(录入年龄时超出范围,录入年龄时录入了abc等情况)
import java.util.Scanner;
public class Exception {
public static void main(String[] args) {
GirlFriend gf = new GirlFriend();
Scanner sc = new Scanner(System.in);
//将判断age和name是否符合条件的代码写到了GirlFriend类当中
while (true) {
try {
System.out.println("age:");
int age = Integer.parseInt(sc.nextLine());
gf.setAge(age);
System.out.println("name:");
gf.setName(sc.next());
break;
} catch (NumberFormatException e) {
System.out.println("年龄输入错误,请输入数字");
} catch (RuntimeException e) {
System.out.println("姓名的长度或年龄的大小不符合条件");
}
}
System.out.println(gf);
}
}
GirlFriend:
public class GirlFriend {
private String name;
private int age;
public GirlFriend() {
}
public GirlFriend(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
if (name.length() < 3 || name.length() > 10) {
throw new RuntimeException();
}
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 18 || age > 40) {
throw new RuntimeException();
}
this.age = age;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
七.自定义异常
1.应用场景:
因为有时我们不知道在出现一种异常时应该使用什么样的系统定义的异常来表示,所以需要自定义异常来描述自己可能会遇到的异常出现的情况
2.自定义异常的步骤
(1).定义异常类
(2).写继承关系(如果是运行时异常那就继承RuntimeException,如果是编译时异常那就继承Exception)
(3).空参构造
(4).带参构造
意义:让控制台的报错信息更加的见名知意
import java.util.Scanner;
public class Exception {
public static void main(String[] args) {
GirlFriend gf = new GirlFriend();
Scanner sc = new Scanner(System.in);
//将判断age和name是否符合条件的代码写到了GirlFriend类当中
while (true) {
try {
System.out.println("age:");
int age = Integer.parseInt(sc.nextLine());
gf.setAge(age);
System.out.println("name:");
gf.setName(sc.next());
break;
} catch (NumberFormatException e) {
//System.out.println("年龄输入错误,请输入数字");
e.printStackTrace();
} catch (NameFormatException e) {
//System.out.println("年龄输入错误,请输入数字");
e.printStackTrace();
} catch (AgeOutOfBoudsException e) {
//System.out.println("姓名的长度或年龄的大小不符合条件");
e.printStackTrace();
}
}
System.out.println(gf);
}
}
GirlFriend:
public class GirlFriend {
private String name;
private int age;
public GirlFriend() {
}
public GirlFriend(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
if (name.length() < 3 || name.length() > 10) {
throw new NameFormatException(name + "格式有误,长度应该为3-10");
}
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 18 || age > 40) {
throw new AgeOutOfBoudsException(age + "大小超出了范围");
}
this.age = age;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}