头图
本文参与了思否技术征文,欢迎正在阅读的你也加入。

异常

异常的概述


  • 异常就是不正常的意思,Java语言中主要是指程序在运行阶段产生的错误
  • Throwable(可抛出的,可扔出的)

    • java.lang.Throwable 类是Java程序所有错误或异常的超类
    • 主要有两个字类

      • Error

        • Error主要描述比较严重的错误
        • 无法通过编程来解决的重大的错误
      • Exception

        • Exception主要m描述比较轻量级的错误
        • 可以通过编程来解决

Exception类的主要分类

RuntimeException -> 运行时异常,也叫非检测性异常类


  • 非检测性异常类就是指b编译阶段无法被编译器检测出来的异常
  • 主要子类

    • ArithmeticException -> 算数异常类
    • ArrayIndexOutOfBoundsException(间接子类) -> 数组下标异常类
    • NullPointerException -> 空指针异常
    • ClassCastException -> 类型转换异常
    • NumberFormatException(间接子类)-> 数字格式异常
  • 注意

    • 当程序的执行过程中产生异常,若没有手动进行处理,则由Java虚拟机采用默认的方式进行处理,默认方式是打印异常名称、异常原因以及异常发生的位置并终止程序,后序代码无法被执行

IOException和其他异常类 -> 其他异常类,也叫做非检测性异常

案例

TestRuntimeException.java

package demo1;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

/*
 *         ArithmeticException -> 算数异常类
        ArrayIndexOutOfBoundsException(间接子类) -> 数组下标异常类
        NullPointerException -> 空指针异常
        ClassCastException -> 类型转换异常
        NumberFormatException(间接子类)-> 数字格式异常
 */

public class TestRuntimeException {
    public static void main(String[] args) {
        
        
        // 观察检测性异常
        // FileInputStream fis = new FileInputStream("c:/a.txt");
    
        // java.lang.ArithmeticException 算数异常
        int a = 10; 
        int b = 0;
        if (b != 0) {
            System.out.println(a/b);
        }

        // java.lang.ArrayIndexOutOfBoundsException 数组下标越界异常

        int[] arr = new int[3];
        int num = 3;
        if (num >= 0 && num < arr.length) {
            System.out.println(arr[num]);
        }
 

        // java.lang.NullPointerException

        String str = null; 
        if (str != null) {
            System.out.println(str.length());
        }

        // java.lang.ClassCastException

        Exception ex = new Exception(); 
        if (ex instanceof IOException) {
            IOException ie = (IOException) ex;
        }

        // java.lang.NumberFormatException

        String s = "12be"; 
        if (s.matches("\\d+")) {
            System.out.println(Integer.parseInt(s));
        }
        System.out.println("运行程序结束");

    }
}

异常处理

运行时异常的处理方式


  • 对于绝大数运行时异常来说,都可以通过条件判断避免异常的发生

异常的捕获


  • 语法格式

      try{
          可能产生异常对象的语句块
      }catch(异常类型 引用名){
          针对当前异常类型对象的处理语句块
      }
      .... (可以写多个catch)
      finally{
          无论是否发生异常,都应该执行的语句块
      }
    
  • 注意事项

    • 当捕获的结构中有多个catch分支时,切记小范围的异常类型放在大范围的异常类型上面
    • 懒人写法:
      catch(Exception e) {....}
  • 执行流程
    try {
        a;
        b;  // 可能产生异常的语句
        c;
    } catch (Exception e) {
        e;
    } finally {
        f;
    }
    
- 当没有产生异常的时候,程序的执行流程是:a b c f 
- 当产生异常时,程序的执行流程是: a b e f 
  • 案例

    • TestExceptionCatch.java

      package demo2;
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      import java.io.IOException;
      
      public class TestExceptionCatch {
      public static void main(String[] args) {
      
          // 声明引用指向本类的对象,用于读取文件中的内容
          FileInputStream fis = null;
          try {
              // 随时可能产生文件找不到y异常对象, new FileNotFoundException()
              fis = new FileInputStream("d:/a.txt");
          } catch (FileNotFoundException e) {
              // 打印异常的名称、异常原因、异常的位置等信息
              e.printStackTrace();
          }
          
          try {
              fis.close();
          } catch (IOException e) {
              
              e.printStackTrace();
          } catch (NullPointerException e) {
              // System.out.println("输出");
              e.printStackTrace();
          }
      }
      }
      
    • TestFinally.java

      package demo3;
      
      public class TestFinally {
      public static void main(String[] args) {
          int a = 10;
          int b = 0;
          
          try {
              System.out.println(a/b);
          } catch (Exception e) {
              e.printStackTrace();
              return ;
          } finally {
              System.out.println("无论是否发生异常都会执行");
          }
          System.out.println("程序结束");
      }
      }
      

      java.lang.ArithmeticException: / by zero
      无论是否发生异常都会执行
      at demo3.TestFinally.main(TestFinally.java:9)

异常的抛出

  • 基本概念

    • 某些特殊的场合中,当产生异常后却无法直接处理/不想处理时,此时就可以将异常转移给当前方法的调用者,这就叫异常的抛出
  • 语法格式

    • 返回值类型 方法名称(形参列表) throws 异常类型{....}
  • 方法重写的原则

    • 要求方法名相同、参数列表相同、返回值类型也相同,从jdk1.5开始允许返回子类类型
    • 范围权限不能变小,可以相同或者变大
    • 不能抛出更大的异常
    • 注意

      • 子类中重写以后的方法可以选择抛出与父类一样的异常、更小的异常、不抛出异常,但是不能抛出更大的异常、不同的异常
      • 案例
        A.java

        package demo4;
        
        import java.io.IOException;
        
        public class A {
            public void show() throws IOException{
                System.out.println("A");
            }
        }
        

        SubA.java

        package demo4;
        
        import java.io.IOException;
        import java.io.FileNotFoundException;
        import javax.print.PrintException;
        
        public class SubA extends A{
        
            @Override
            // public void show() throws IOException {
            // public void show() throws FileNotFoundException {
            // public void show() throws PrintException {
            // public void show() throws Exception {
            public void show() {
            }
        }
        
        显然不能抛出更大的异常

自定义异常

  • 自定义异常的由来

    • Java官方库中虽然提供了大量的异常类,但不足以描述现实生活中所有的异常情况。当出现官方库中没有m描述的异常情况,这个时候就需要程序员自定义异常类加以描述,使得异常信息更加具备针对性和可读性
  • 自定义异常的流程

    • 自定义类继承自Exception类或者Exception类的子类
    • 提供两个版本的构造方法,一个是无参构造方法,另一个是字符串做参数的构造方法
  • 自定义异常 -- >案例1

    • Person.java

      package demo5;
      
      public class Person {
      private String name;
      private int age;
      
      
      
      public Person() {
          super();
      }
      public Person(String name, int age) throws Exception {
          super();
          setName(name);
          setAge(age);
      }
      public String getName() {
          return name;
      }
      public void setName(String name) {
          this.name = name;
      }
      public int getAge() {
          return age;
      }
      public void setAge(int age) throws Exception {
          if(age > 0 && age < 150) {
              this.age = age;
          } else {
              // System.out.println("年龄不合理");
              // 手动产生一个异常对象并抛出
              // throw new Exception();
              throw new AgeException("年龄不合理!");
          }
          System.out.println("产生异常的效果");
      }
      @Override
      public String toString() {
          return "Person [name=" + name + ", age=" + age + "]";
      }
      
      
      }
      
    • AgeException.java

      package demo5;
      
      public class AgeException extends Exception {
      
      /**
       * 
       */
      private static final long serialVersionUID = 1L;
      
      // 自定义无参的构造方法
      public AgeException() {
          
      }
      
      // 自定义使用字符串作为参数的构造方法
      public AgeException(String msg) {
          super(msg);
      }
      }
      
    • TestPerson.java

      package demo5;
      
      public class TestPerson {
      public static void main(String[] args) {
      
          Person p = null;
          try {
              p = new Person("张三", -12);
          } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          System.out.println(p);
      }
      }
      

      demo5.AgeException: 年龄不合理!
      null
      at demo5.Person.setAge(Person.java:33)
      at demo5.Person.<init>(Person.java:15)
      at demo5.TestPerson.main(TestPerson.java:8)

  • 自定义异常 -- > 案例2

    • Student.java

      package demo6;
      
      public class Student {
      private String name;
      private int id;
      
      
      public Student() {
          super();
      }
      public Student(String name, int id) throws IDException {
          super();
          setName(name);
          setId(id);
      }
      public String getName() {
          return name;
      }
      public void setName(String name) {
          this.name = name;
      }
      public int getId() {
          return id;
      }
      public void setId(int id) throws IDException {
          if (id > 0) {
              this.id = id;
          } else {
              // System.out.println("学号不合理");
              throw new IDException("学号不合理");
          }
          System.out.println("结束");
      }
      @Override
      public String toString() {
          return "Student [name=" + name + ", id=" + id + "]";
      }
      
      
      }
      
    • IDException.java

      package demo6;
      
      public class IDException extends Exception {
      
      /**
       * 
       */
      private static final long serialVersionUID = 1L;
      
      public IDException() {
          
      }
      
      public IDException(String msg) {
          super(msg);
      }
      }
      
    • TestStudent.java

      package demo6;
      
      public class TestStudent {
      public static void main(String[] args) throws IDException {
          
          /*Student stu = null;
          try {
              stu = new Student("小王", -5);
          } catch (IDException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }*/ 
          
          Student stu = new Student("小王", -5);
          System.out.println(stu);
      }
      }
      

      Exception in thread "main" demo6.IDException: 学号不合理
      at demo6.Student.setId(Student.java:30)
      at demo6.Student.<init>(Student.java:14)
      at demo6.TestStudent.main(TestStudent.java:14)

此处有一点要注意,在案例一的TestPerson中,在main函数中,我们使用try....catch语句,异常由内部进行处理,会打印后面的语句
而在案例二的TestStudent中,我们将异常直接交给main函数处理,也就是交给虚拟机处理,所以并不会执行后面的语句

异常对象的抛出

  • throw new 异常类型()
  • 例如:

    • throw new Exception()
最后简单介绍一下throws和throw的区别

throws和throw的区别

  • throws

    • 用在方法声明后面,跟的是异常类名
    • 可以跟多个异常类名,用逗号隔开
    • 表示抛出异常,由该方法的调用者来处理
    • throws表示出现异常的一种可能性,并不一定会发生这些异常
  • throw

    • 用在方法体内,跟的异常对象名
    • 只能抛出一个异常对象名
    • 表示抛出异常,由方法体内的语句实现
    • throw则是抛出了异常,执行throw则一定抛出了某种异常

若尘
54 声望10 粉丝