异常

什么是异常?

  • 异常就是程序出现了一些错误,可以简单理解为出现阻止当前方法或者作用域的情况。
  • 程序执行时出现错误的时候,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来处理

异常执行流程图

image.png

自定义异常
为了符合业务需求,可以自定义异常。可以通过异常的类名更加明确异常的原因,方便观看和分析

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)

你可能感兴趣的:(异常)