Java-异常-06

一、异常

1.1、异常概述

  • 异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。
  • 异常发生在程序运行期间,它影响了正常的程序执行流程。

1.2、简单分类

  • 编译时异常(又称受检异常):必须显示处理,否则程序就会发生错误,无法通过编译。

    • 例如:要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常(又称非受检异常):无需显示处理,也可以和编译时异常一样处理。

    • 所有的 RuntimeException 类及其子类被称为运行时异常。

    • 例题:

      public static void main(String[] args) {
      //method();
      method2();
      }
      
      // 编译时异常
      public static void method2() {
        try {
            String s = "2020-12-9";
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date d = null;
            d = sdf.parse(s);
            System.out.println(d);
        } catch (ParseException e) {
            e.printStackTrace();
        }
      }
      
      // 运行时异常
      public static void method() {
        try {
            int[] arr = {1, 2, 3};
            System.out.println(arr[arr[3]]);    //ArrayIndexOutOfBoundsException
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
      }
      
  • 错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。

    • 例如:当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

1.3、异常体系结构

  • Java 把异常当作对象来处理,并定义一个基类 java.lang.Throwable 作为所有异常的超类。
  • 在 Java API 中已经定义了许多异常类,这些异常类分为两大类,错误 Error 和异常 Exception。

1.3.1、Error

  • Error 类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
  • Java 虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止

1.3.2、Exception

  • 在 Exception 分支中有一个重要的子类 RuntimeException(运行时异常)
    • ArraylndexOutOfBoundsException(数组下标越界)
    • NullPointerException(空指针异常)
    • ArithmeticException(算术异常)
    • MissingResourceException(丢失资源)
    • ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
  • 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
  • Error 和 Exception 的区别:Error 通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java 虚拟机(JVM)一般会选择终止线程;Exception 通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。

1.4、JVM默认的处理方案

  • 如果程序出现了问题,我们没有做任何处理,最终 JVM 会做默认的处理。
    • 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台。
    • 程序停止执行。

1.5、异常处理机制

  • 抛出异常
  • 抓取异常

1.5.1、异常处理的五个关键字

1.5.1.1、try...catch 与 finally

  • try:设置异常的监控区域。
  • catch:出现异常时,按照给定的异常进行捕获。
  • finally:不管程序是否出现异常都执行。
    • 假设要捕获多个异常:cath() 中的异常要从小到大

    • 格式:

      try{
        // 可能出现异常的代码;
      }catch(异常类名 变量名){
        // 异常的处理代码。
      }
      
    • 例题:

      // try...catch... 与 finally
      public static void main(String[] args) {
        int a = 1;
        int b = 0;
      
        try {
            System.out.println(a/b);
        }catch (ArithmeticException e){ 
            System.out.println("程序出现错误,变量 b 不能为 0");
              // 打印错误的栈信息
              e.printStackTrace();
        }finally {
            System.out.println("finally");
        }
      }
      

1.5.1.2、throw

  • throw:主动抛出异常
    • 例题:

      // throw
      public static void main(String[] args) {
          new Dome01().test(1,0);
      
      }
      public void test(int a,int b){
          if (b == 0){
              // 出动抛出异常,一般用在方法中
              throw new ArithmeticException();
          }
      }
      

1.5.1.3、throws

  • throws:往上抛出异常

    • 格式:

      throws 异常类名
      
    • 例题:

      public static void main(String[] args) {
            // 把异常抛到此处
            try {
                new Dome01().test(1,0);
            } catch (ArithmeticException e) {
                e.printStackTrace();
            }
      }
      
      // throws 往上抛出异常
      public void test(int a,int b)throws ArithmeticException {
          System.out.println(a/b);
      }
      
  • throws 和 throw 的区别

    • throws:
      • 用在方法声明后面,跟的是异常类名。
      • 表示抛出异常,由该方法的调用者来处理。
      • 表示出现异常的一种可能性,并不一定会发生这些异常。
    • throw:
      • 用在方法体内,跟的是异常对象名。
      • 表示抛出异常,由方法体内的语句处理。
      • 执行 throw 一定抛出了某种异常。

1.6、Throwable 的成员方法

方法名 说明
public String getMessage() 返回此 throwable 的详细消息字符串
public String toString() 返回此可抛出的简短描述
public void printStackTrace() 把异常的错误信息输出在控制台

1.6.1、getMessage() 方法

public static void main(String[] args) {
    System.out.println("开始");
    method();
    System.out.println("结束");
}
public static void method(){
    try{
        int[] arr={1,2,3};
        System.out.println(arr[10]);
    }catch (ArrayIndexOutOfBoundsException e){

        System.out.println(e.getMessage());
    }
}

1.6.2、toString() 方法

public static void main(String[] args) {
    System.out.println("开始");
    method();
    System.out.println("结束");
}
public static void method(){
    try{
        int[] arr={1,2,3};
        System.out.println(arr[10]);
    }catch (ArrayIndexOutOfBoundsException e){

        System.out.println(e.toString());
    }
}

1.6.3、printStackTrace() 方法

public static void main(String[] args) {
    System.out.println("开始");
    method();
    System.out.println("结束");
}
public static void method(){
    try{
        int[] arr={1,2,3};
        System.out.println(arr[10]);
    }catch (ArrayIndexOutOfBoundsException e){

        e.printStackTrace();
    }
}

1.7、自定义异常

  • 自定义异常类需要继承 Exception

  • 格式:

    public class 异常类名 extends Exception{
      无参构造
      带参构造
    }
    
  • 语法:

    // 自定义异常类
    public class Dome02 extends Exception {
    
      // 传递数字 > 10
      private String detail;
    
      public Dome02(){}
      public Dome02(String a) {
          this.detail = a;
      }
    
      // 重写 to String() 方法:异常的打印信息
      @Override
      public String toString() {
          return "Dome02{" + detail + '}';
      }
    }
    
    // 测试类
    public static void main(String[] args) {
        try {
            test(1);
        } catch (Dome02 dome02) {
            // System.out.println("Dome02=>"+dome02);
            dome02.printStackTrace();
        }
    }
    
    static void test(int a) throws Dome02 {
        System.out.println("传递的参数为:" + a);
    
        // 如果 a 大于 10则输出异常
        if(a>10){
            // 主动抛出异常
            throw new Dome02("你输入了 >10 的数字"); // 提示信息
        }
    
        System.out.println("OK");
    }
    
  • 实际应用中的经验总结

    • 处理运行时异常时,采用逻辑去合理规避同时辅助 try-catch 处理
    • 在多重 catch 块后面,可以加一个 catch(Exception) 来处理可能会被遗漏的异常
    • 对于不确定的代码,也可以加上 try-catch,处理潜在的异常
    • 尽量去处理异常,切忌只是简单地调用 printStackTrace() 去打印输出
    • 具体如何处理异常,要根据不同的业务需求和异常类型去决定
    • 尽量添加 finally 语句块去释放占用的资源
posted @ 2021-02-20 09:31    阅读(49)  评论(0)    收藏  举报