异常(十六)


异常(十六)

异常就是代表程序出现的问题。

作用

  1. 异常是用来查询bug的关键参考信息
  2. 异常可以作为方法内部的一种特殊返回值,通知调用者底层的执行情况

异常体系

java.lang.Throwable

  • Error:代表的系统级别错误(属于严重问题),开发人员不用去管
  • Exception:就是常说的异常,代表程序可能会出现的问题,通常用Exception以及他的子类来封装程序出现的问题
    • 编译时异常:并未继承RuntimeException的异常,直接继承于Exception,编译阶段就会出现错误提示
    • 运行时异常:RuntimeException及其子类,编译阶段不会出现异常提醒,而是运行时出现的异常。

运行时异常和编译时异常

  • java文件通过javac命令进行编译,编译成字节码文件,该过程称为编译阶段,编译阶段就要进行处理的异常就是编译时异常
    • 编译阶段:java不会运行代码,只会检查语法是否错误,或者做一些性能的优化,更多是在提醒程序员检查本地信息
  • 字节码文件通过java命令运行代码,在运行时出现的异常就是运行时异常
    • 代码出错而导致程序出现问题

异常的处理方式

  1. JVM默认的处理方式
  2. 自己处理(捕获异常)
  3. 抛出异常

JVM默认的处理方式

把异常的名称,异常原因及异常出现的位置等信息输出在控制台,程序停止执行,下面的代码不会再执行。

自己处理(捕获异常)

格式1

1
2
3
4
5
try{
//可能会出现异常的代码
}catch(异常类名 变量名){
//异常的处理代码
}

目的:当代码出现异常时,可让程序继续往下执行。

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Test{
public static void main(String[] args){
int[] arr={1,2,3,4,5,6};
try {
//可能出现异常的代码
System.out.println(arr[10]);
//此处出现异常
//程序就会创建ArrayIndexOutOfBoundsException的对象
//new ArrayIndexOutOfBoundsException
//用该对象和catch括号中变量进行对比,测试变量是否能接收该对象
//若不可被接收,报错并停止运行程序
//若可被接收,表示该异常被捕获(抓住),执行catch对应的代码
//当catch里的所有代码执行完毕,继续继续try...catch体系下的其他代码
}catch (ArrayIndexOutOfBoundsException a){
System.out.println("索引越界");
}
System.out.println("测试是否执行");
}
}
/*
索引越界
测试是否执行
*/

  • 若try中代码并未遇到问题,会将try中所有代码执行完毕,不会执行catch中的代码
  • 若try中可能会出现多个问题,就要写多个catch与之对应
    • 注:若要捕捉多个异常,多个异常中存在父子关系,父类一定要写下面
    • 在JDK7后,可在一个catch中同时捕获多个异常,中间用|进行隔开,表示若出现A或B异常,采取同一种处理方案
  • 若try中问题并未被捕获,会终止当前程序,异常会交给虚拟机处理
  • try中现异常,则try中下面的语句不会再执行,会直接转到相应的catch,若没有catch与之匹配,则交给虚拟机处理

格式2

1
2
3
4
5
6
7
try{
//可能会出现异常的代码
}catch(异常类名 变量名){
//异常的处理代码
}finally{
//这里代码必定执行,除非虚拟机关闭
}

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Test{
public static void main(String[] args){
int[] arr={1,2,3,4,5,6};
try {
System.out.println(arr[10]);
}catch (ArrayIndexOutOfBoundsException a){
System.out.println("索引越界");
}finally {
System.out.println("测试是否执行");
}
System.out.println();
try {
System.out.println(arr[1]);
}catch (ArrayIndexOutOfBoundsException a){
System.out.println("索引越界");
}finally {
System.out.println("测试是否执行");
}
System.out.println();
try {
System.exit(0);
System.out.println(arr[1]);
}catch (ArrayIndexOutOfBoundsException a){
System.out.println("索引越界");
}finally {
System.out.println("测试是否执行");
}
}
}
/*
索引越界
测试是否执行

2
测试是否执行


*/

抛出异常

throws

写在方法定义处,表示声明一种异常,告诉调用者,使用本方法可能会出现哪些异常。

编译时异常:必须要写。

运行时异常:可以不写。

格式

1
2
3
public void 方法()throws 异常类名1,异常类名2...{

}

throw

写在方法内,结束方法,手动抛出异常对象,交给调用者,方法中下面的代码不再执行。

格式

1
2
3
public void 方法(){
throw new 异常类名;
}

区别

  1. throws用于方法头,表示的只是异常申明,而throw用于方法内部,抛出的是异常对象。
  2. throws可一次性抛出多个异常,throw只能一个。
  3. throws抛出异常时,它的调用者也要申明抛出异常或捕获,不然编译报错,而throw可以不申明或不捕获,但编译器不会报错。

常见方法

getMessage

格式

public String getMessage()

说明:返回此throwable的详细消息字符串

toString()

格式

public String toString()

说明:返回此可抛出的简短描述

printStackTrace

格式

public void printStackTrace()

说明:在底层是利用System.err.println进行输出,把异常的错误信息以红色字体输出在控制台,仅仅是打印信息,不会停止程序运行

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Test{
public static void main(String[] args){
int[] arr={1,2,3,4,5,6};
try {
System.out.println(10/0);
}catch (ArithmeticException a){
System.out.println("getMessage方法");
System.out.println(a.getMessage());
System.out.println();

System.out.println("toString方法");
System.out.println(a.toString());
System.out.println();

System.out.println("printStackTrace方法");
a.printStackTrace();
System.out.println();
}
System.out.println("测试是否执行");
}
}
/*
getMessage方法
/ by zero

toString方法
java.lang.ArithmeticException: / by zero

printStackTrace方法
java.lang.ArithmeticException: / by zero
at Test.main(Test.java:5)

测试是否执行
*/

自定义异常

步骤

  1. 定义异常类,类名要见名知意
  2. 写继承关系
    • 运行时异常要继承RuntimeException
    • 编译时异常要继承Exception
  3. 空参构造
  4. 带参构造

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
需求:
键盘录入学生的姓名和年龄
姓名长度在3-10之间
年龄范围在18-40岁之间
超出这个范围是异常数据不能赋值,需重新录入,一直录到正确为止
提示:
需要考虑用户在键盘录入时的所有情况
比如:录入年龄时超出范围,录入年龄时录入abc等情况
*/
//Test.java
import java.util.Scanner;

public class Test{
public static void main(String[] args){
Scanner s=new Scanner(System.in);
Student stu=new Student();
while (true) {
try {
System.out.print("请输入学生姓名:");
String name=s.nextLine();
stu.setName(name);

System.out.print("请输入学生年龄:");
int age=Integer.parseInt(s.nextLine());
stu.setAge(age);
break;
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (NameLengthException e){
e.printStackTrace();
} catch (AgeRangeException e){
e.printStackTrace();
}
}
System.out.println(stu);
}
}

//AgeRangeException.java
public class AgeRangeException extends RuntimeException {
public AgeRangeException() {
}

public AgeRangeException(String message) {
super(message);
}
}

//NameLengthException.java
public class NameLengthException extends RuntimeException{
public NameLengthException() {
}

public NameLengthException(String message) {
super(message);
}
}

//Student.java
public class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
int length=name.length();
if(length<3 || length>10){
throw new NameLengthException("姓名长度为"+length+",不符合范围");
}

this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
if(age<18||age>40){
throw new AgeRangeException("年龄为"+age+",不符合范围");
}
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}

/*
请输入学生姓名:aa
NameLengthException: 姓名长度为2,不符合范围
at Student.setName(Student.java:28)
at Test.main(Test.java:11)
请输入学生姓名:aaaaaaaaaaaaaaaa
NameLengthException: 姓名长度为16,不符合范围
at Student.setName(Student.java:28)
at Test.main(Test.java:11)
请输入学生姓名:zhangsan
请输入学生年龄:8
AgeRangeException: 年龄为8,不符合范围
at Student.setAge(Student.java:48)
at Test.main(Test.java:15)
请输入学生姓名:zhangsan
请输入学生年龄:50
AgeRangeException: 年龄为50,不符合范围
at Student.setAge(Student.java:48)
at Test.main(Test.java:15)
请输入学生姓名:zhangsan
请输入学生年龄:aaa
java.lang.NumberFormatException: For input string: "aaa"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at Test.main(Test.java:14)
请输入学生姓名:zhangsan
请输入学生年龄:20
Student{name = zhangsan, age = 20}
*/

Author: ljs
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source ljs !
评论
  TOC