Java中的异常处理

概念

  • 如果某个方法不能按照正常的途径完成任务,就可以通过另一种路径退出方法。

  • 在这种情况下会抛出一个封装了错误信息的对象。

  • 此时这个方法会立刻退出同时不返回任何值。

  • 调用这个方法的其他代码也无法继续执行,异常处理机制会将代码执行交给异常处理器。

Java异常类层次结构

  • Throwable 是 Java 语言中所有错误或异常的超类。

  • Error 类是指 java 运行时系统的内部错误和资源耗尽错误,应用程序不会抛出该类对象。

  • Exception(RuntimeException、CheckedException)又有两个分支:

    • RuntimeException:运行时异常,如 NullPointerException、ClassCastException。

    • CheckedException:检查异常,如 I/O 错误导致的 IOException、SQLException。

  • RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。

  • CheckedException 一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序去捕获此类异常。

Error(错误)

  • Error(错误)是程序无法处理的错误,表示运行应用程序中较严重问题。

  • 大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。

  • 这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

  • Error 表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时。

  • 这些错误是不可查的,因为它们在应用程序的控制和处理能力之外。

  • 对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。

  • 在 Java 中,错误通过 Error 的子类描述。

  • 例如

    public class ErrorExample {
        public static void main(String[] args) {
            // 触发 StackOverflowError(Error 的子类)
            recursiveMethod(0);
        }
    
        // 无限递归导致栈溢出,触发 Error
        private static void recursiveMethod(int counter) {
            System.out.println("Counter: " + counter);
            recursiveMethod(counter + 1); // 无终止条件,最终抛出 StackOverflowError
        }
    }
     
    

Exception(异常)

  • Exception(异常)是程序本身可以处理的异常。

  • 异常和错误的区别:异常能被程序本身处理,错误是无法处理。

  • Exception(RuntimeException、CheckedException)又有两个分支:RuntimeException 和 CheckedException。

  • RuntimeException 是可能在 Java 虚拟机正常运行期间抛出的异常的超类,如 NullPointerException、ClassCastException。

  • 例如

    public class RuntimeExceptionExample {
        public static void main(String[] args) {
            String str = null;
            try {
                System.out.println(str.length());
            } catch (NullPointerException e) {
                System.out.println("Caught NullPointerException: " + e.getMessage());
            }
        }
    }
     
    
  • CheckedException 一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序去捕获此类异常,包括试图在文件尾部读取数据、试图打开一个错误格式的 URL、试图根据给定的字符串查找 class 对象,而这个字符串表示的类并不存在等。

  • 例如

    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class CheckedExceptionExample {
        public static void main(String[] args) {
            File file = new File("nonexistent.txt");
            try {
                FileReader fr = new FileReader(file);
            } catch (IOException e) {
                System.out.println("Caught IOException: " + e.getMessage());
            }
        }
    }
     
    

Throwable 类常用方法

  • Throwable 类常用方法:

    • getMessage():返回异常发生时的详细信息。

    • toString():返回异常发生时的简要描述。

    • getLocalizedMessage():返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同。

    • printStackTrace():在控制台上打印 Throwable 对象封装的异常信息。

异常处理总结

  • try 块:用于捕获异常,可以接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。

  • catch 块:用于处理 try 块捕获到的异常。

  • finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。

  • 当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。

  • 特殊情况下,finally 块可能不会被执行:

    • 在 finally 语句块中发生了异常。

    • 在前面的代码中使用了 System.exit() 退出程序。

    • 程序所在的线程死亡。

    • 关闭 CPU(该情况不太可能发生)。

  • 例如:

    try-catch-finally 基本结构

    try {
        // 可能抛出异常的代码
        int result = 10 / 0;
    } catch (ArithmeticException e) {
        // 处理特定异常
        System.out.println("捕获到算术异常: " + e.getMessage());
    } finally {
        // 无论是否发生异常都会执行
        System.out.println("finally 块执行");
    }
    

    多个 catch 块

    try {
        String str = null;
        System.out.println(str.length());
    } catch (NullPointerException e) {
        System.out.println("空指针异常: " + e);
    } catch (Exception e) {
        System.out.println("通用异常处理: " + e);
    }
    

    try-finally 结构

    try {
        // 没有 catch 块
        System.out.println("try 块执行");
    } finally {
        System.out.println("finally 块执行");
    }
    

    return 与 finally 的执行顺序

    public static int testFinally() {
        try {
            return 1;
        } finally {
            System.out.println("即使有 return,finally 也会执行");
        }
    }
    

    finally 不被执行的情况

    try {
        System.exit(0); // 程序退出,finally 不会执行
    } finally {
        System.out.println("这段代码不会执行");
    }
    

Throw和Throws的区别

  • 位置不同:

    • throws 用在函数上,后面跟的是异常类,可以跟多个

    • public class ThrowsExample {
          // 在方法签名中使用throws声明可能抛出的异常类型
          public static void readFile() throws FileNotFoundException {
              File file = new File("nonexistent.txt");
              FileInputStream fis = new FileInputStream(file); // 可能抛出FileNotFoundException
          }
      
          public static void main(String[] args) {
              try {
                  readFile(); // 调用者需处理声明的异常
              } catch (FileNotFoundException e) {
                  System.out.println("文件未找到: " + e.getMessage());
              }
          }
      }
       
      
    • 而 throw 用在函数内,后面跟的是异常对象。

    • public class ThrowExample {
          public static void checkAge(int age) {
              if (age < 18) {
                  // 在方法体内使用throw抛出具体异常对象
                  throw new ArithmeticException("年龄未满18岁"); // 抛出运行时异常
              }
              System.out.println("允许访问");
          }
      
          public static void main(String[] args) {
              try {
                  checkAge(15); // 抛出异常后,后续代码不会执行
              } catch (ArithmeticException e) {
                  System.out.println("捕获异常: " + e.getMessage());
              }
          }
      }
       
      
  • 功能不同:

    • throws 用来声明异常,让调用者只知道该功能可能出现的问题,可以给出预先的处理方式;throw 抛出具体的问题对象,执行到 throw,功能就已经结束了,跳转到调用者,并将具体的问题对象抛给调用者。也就是说 throw 语句独立存在时,下面不要定义其他语句,因为执行不到。

    • throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw 则是抛出了异常,执行 throw 则一定抛出了某种异常对象。

  • 两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值