1.什么是异常
异常就是代码中出现的问题。
代码中经常会出异常,我们要考虑的是如果出现异常应该怎么解决,而不是防止出现异常。
2.异常体系结构
Error:代表系统级别的错误(属于严重的问题),比如内存溢出,或者什么硬件问题等等。我们代码层面管不了,所以不用管。
3.Exception
-
Exception:代表程序可能出现的问题。我们通常会用Exception和它的子类来封装程序可能出现的问题。 Eexception包含两类异常,分别是
RuntimeExcepton(运行时异常)和其它异常(编译时异常)。 -
RuntimeException:只有程序运行的时候才会发生,编译阶段不会出现异常。比如下面图片中的数组索引越界异常,因为程序没有执行,所以还没有发生异常:
编译时异常:这类异常在编译阶段就发生,比如下面图片中就出现了一个编译时异常,因为属于编译时异常,所以程序没有运行就发生了,idea就给出了error提示:
4.两类异常的区别
- 编译时异常:提醒程序员检查本地信息,比如下面代码:
这里的作用就是提醒程序员
a.txt文件是否存在,如果不存在就会出现异常。
- RuntimeException(运行时异常):代码出错而导致的问题。
5.异常的作用
- 异常是查询bug的关键信息。
- 异常可以作为方法内部的特殊返回值,以便通知调用者底层的执行情况。
第二个作用怎么理解呢?
比如我有个GrilFriend类:
package com.akbar.exception;
public class GrillFried {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
if (age <20 || age > 30) {
throw new RuntimeException();
}
this.age = age;
}
}
我给GrillFried赋值的时候,如果年龄小于20或者大于30就通知调用者执行情况:
package com.akbar.exception;
public class HandlerException {
public static void main(String[] args) {
GrillFried grillFried = new GrillFried();
grillFried.setName("小惠惠");
grillFried.setAge(15);
}
}
调用者可以自由选择异常处理方式,比如:
- 打印在控制台上(默认)
- 自己悄悄处理掉
6.异常的处理方式
- jvm默认处理方式(把异常信息用红色字体输出,程序会停止)
- 自己处理
- 抛出异常(交给调用者)
自己处理异常(捕获异常)
比如:
package com.akbar.exception;
public class HandlerException {
public static void main(String[] args) {
GrillFried grillFried = new GrillFried();
grillFried.setName("小惠惠");
try {
grillFried.setAge(15);
} catch (RuntimeException e) {
System.out.println("年龄必须在20到30之间");
}
System.out.println("姓名:" + grillFried.getName() + " 年龄:" + grillFried.getAge());
}
}
也可以写多个catch:
package com.akbar.exception;
public class HandlerException {
public static void main(String[] args) {
GrillFried grillFried = new GrillFried();
grillFried.setName("小惠惠");
try {
grillFried.setAge(15);
} catch (ArithmeticException e) {
System.out.println("年龄必须是数字");
} catch (RuntimeException e) {
System.out.println("年龄必须在20到30之间");
}
System.out.println("姓名:" + grillFried.getName() + " 年龄:" + grillFried.getAge());
}
}
7.异常中常见的方法
比如:
package com.akbar.exception;
public class HandlerException {
public static void main(String[] args) {
GrillFried grillFried = new GrillFried();
grillFried.setName("小惠惠");
try {
grillFried.setAge(15);
} catch (RuntimeException e) {
e.printStackTrace();
}
System.out.println("姓名:" + grillFried.getName() + " 年龄:" + grillFried.getAge());
}
}
8.抛出异常
9.自定义异常
我想验证grillFried的属性,比如女朋友的名字必须是英文,年龄必须在20到30之间:
分别定义两个自定义异常分别表示姓名的问题和年龄的问题:
NameFormatException:
package com.akbar.exception;
public class NameFormatException extends RuntimeException {
/*
* 如果是运行时异常,要继承RuntimeException
* 如果时编译时异常,要继承Exception
* */
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
AgeFormatException:
package com.akbar.exception;
public class AgeFormatException extends RuntimeException{
/*
* 如果是运行时异常,要继承RuntimeException
* 如果时编译时异常,要继承Exception
* */
public AgeFormatException() {
}
public AgeFormatException(String message) {
super(message);
}
}
注意:
- 如果是运行时异常,要继承RuntimeException
- 如果是编译时异常,要继承Exception
然后在GrilFriend中进行校验:
package com.akbar.exception;
public class GrillFried {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
if (name.isEmpty()) {
throw new NameFormatException("姓名不能为空!");
}
// 姓名只能是英文字母
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
throw new NameFormatException("姓名只能是英文字母!");
}
}
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
if (age <20 || age > 30) {
throw new AgeFormatException("年龄必须在20到30之间!");
}
this.age = age;
}
}
然后在main方法中进行捕获异常并处理:
package com.akbar.exception;
public class HandlerException {
public static void main(String[] args) {
GrillFried grillFried = new GrillFried();
try {
grillFried.setName("小惠惠");
grillFried.setAge(15);
} catch (NameFormatException e) {
System.out.println("姓名格式错误:" + e.getMessage());
} catch (AgeFormatException e) {
System.out.println("年龄格式错误:" + e.getMessage());
} catch (RuntimeException e) {
System.out.println("其它错误:" + e.getMessage());
}
System.out.println("姓名:" + grillFried.getName() + " 年龄:" + grillFried.getAge());
}
}
补充说明:Java的异常分为两大类:
- 检测异常(checked exception):必须显式处理的异常
- 非检测异常(unchecked exception):RuntimeException及其子类,这类异常不强制要求显式处理