Bootstrap

大话Java异常

异常

异常的概述

  • 异常就是不正常的意思,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) {....}

  • 执行流程

  • 当没有产生异常的时候,程序的执行流程是: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.(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.(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则一定抛出了某种异常