什么是异常?
- 异常就是程序出现了一些错误,可以简单理解为出现阻止当前方法或者作用域的情况。
- 程序执行时出现错误的时候,jvm会把执行时出错的信息(例如出错的原因、类型、位置)收集,然后打包成一个对象(Object),程序员可以对这种对象进行处理,这种对象就是所谓的异常
- 但并不是所有错误都是异常。并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常。
异常的三种类型
检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。首先它的过程是在程序把他的.java的源文件编译成字节码文件也就是.class文件出现的异常。 这种异常一定要处理,否则不能通过编译。
运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。 例如除数为0的异常,代码逻辑没问题,但是不符合数学逻辑,即除数为0异常
错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Java异常体系
Throwable:代表可抛出的、Java中所有错误和异常的超类
|-- Error :表示出现错误,严重的问题,程序无法解决 --> 必须处理
|--Exception:表示出现异常 程序可以解决 ----> 可以不处理
|--编译时异常
|--运行时异常
1. Error
是系统级别的严重错误
这种错误程序员无法进行处理, 例如操作系统崩溃, jvm出错, 动态链接库失败等.
Error并不是异常
2. Exception
代表的就是异常. 它下面很多派生类,
其中它的派生类也分两种
一种是RuntimeException(运行时异常),
其他的都是非运行时异常(编译时异常)
虚拟机处理异常的方式
1.把异常对象的类名,异常内容,异常出现的位置信息打印到控制台上
2.终止程序执行
处理异常
2种方式:
1、throws处理异常(作为一个声明,抛出异常,让别人来处理)
2、try...catch (捕获异常,自己处理)
注意:
- throws语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是Exception异常类型,则该方法被声明为抛出所有的异常。
- 当方法抛出异常列表的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,由他去处理。
- try中代码一旦出现异常,try中异常后面的代码不执行,执行紧接它的catch中的代码,然后执行最后catch后面的代码
finally代码块的作用
放在finally中的代码一定会被执行, 一定要执行的代码就放在finally中;在实际开发中,将资源的释放,放在finally.线程的锁,IO流程的关闭
异常常用的3中方法
getMessage: 返回异常的原因
toString: 返回异常的类名和原因
printStackTrace: 有异常的类名,原因和错误的行数
子类和父类异常问题
1、子类重写方法throws的异常要比父类方法throws的异常少
2、子类重写方法throws的异常可以是父类方法throws异常的子类
3、父类方法没有throws异常,子类方法只能try..catch来处理
异常执行流程图
自定义异常
为了符合业务需求,可以自定义异常。可以通过异常的类名更加明确异常的原因,方便观看和分析
1.自定义一个异常类
class S18Exception extends Exception{
// 2、编写构造方法调用父类构造方法
public S18Exception() {
}
public S18Exception(String message) {
super(message);
}
}
2.定义一个注册方法,抛出自定义异常类
public static void regist(String name,int age) throws S18Exception{
if (age < 18){
//年龄太小问题,我们创建一个自定义的异常
throw new S18Exception("太小了,回家喝奶去");
}else {
System.out.println("注册成功,尽情浏览吧");
}
}
}
3.main方法捕捉并处理异常
public class Test {
//网上注册,年龄小于18岁的自定义为异常
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的名字");
String name = sc.next();
System.out.println("请输入你的年龄");
int age = sc.nextInt();
//5、捕捉异常并且处理
try{
regist(name,age);
} catch (S18Exception e) {
e.printStackTrace();
System.out.println("处理了异常");
}
}
年龄小于18输出结果
com.xxx.S18Exception: 太小了,回家喝奶去
at com.xxx.Test.regist(Test.java:xx)
at com.xxx.Test.main(Test.java:xx)
处理了异常
案例二
在一款角色扮演游戏中,每一个人都会有名字和生命值;角色的生命值不能为负数。
要求:当一个人物的生命值为负数的时候需要抛出自定的异常。
class Person{
private String name;
private int lifeValue;
public Person() {
}
/**提供有参构造*/
public Person(String name, int lifeValue) {
super();
setName(name);
setLifeValue(lifeValue);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLifeValue() {
return lifeValue;
}
// 重写这个set方法
public void setLifeValue(int lifeValue){
if (lifeValue < 0){
throw new NotLife("生命值不能为负数" + lifeValue);
}
this.lifeValue = lifeValue;
}
}
自定义异常类
class NotLife extends RuntimeException{
public NotLife(int lifeValue) {
super();
}
public NotLife(String message) {
super(message);
}
}
测试
public class Test {
public static void main(String[] args) {
Person p = new Person("王二小",-100);
// Person p = new Person();
// p.setLifeValue(-100);
// p.getLifeValue();
}
}
输出结果
Exception in thread "main" com.xxx.NotLife: 生命值不能为负数-100
at comxxx.Person.setLifeValue(xxx)
at com.xxx.Person.(xxx)
at com.xxx.main(xxx)