Java异常处理机制

Java异常处理机制

Java是采用面向对象的方式来处理异常的。处理过程:

  1. 抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给JRE。
  2. 捕获异常JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。

异常的分类

  • java.lang.Throwable
    • Error:Error是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。 Error表明系统JVM已经处于不可恢复的崩溃状态中。我们不需要管它。
    • Exception:Exception是程序本身能够处理的异常,Exception类是所有异常类的父类,其子类对应了各种各样可能出现的异常事件。 通常Java的异常可分为:
      • RuntimeException 运行时异常:这类异常通常是由编程错误导致的,所以在编写程序时,并不要求必须使用异常处理机制来处理这类异常,经常需要通过增加“逻辑处理来避免这些异常”。
        • ArithmeticException异常:试图除以0
        • NullPointerException异常:空指针
        • ClassCastException异常:类型转换异常
        • ArrayIndexOutOfBoundsException异常:数组下标越界异常
        • NumberFormatException异常:数字格式异常
      • CheckedException 已检查异常:所有不是RuntimeException的异常,统称为Checked Exception,又被称为“已检查异常”,如IOException、SQLException等以及用户自定义的Exception异常。 这类异常在编译时就必须做出处理,否则无法通过编译。
005

捕获异常

006
  • try:

    当任意一条语句产生异常时,就会跳过该条语句中后面的代码。代码中可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。一个try语句必须带有至少一个catch语句块或一个finally语句块 。

  • catch:

    每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。常用方法,这些方法均继承自Throwable类:

    • toString ()方法,显示异常的类名和产生异常的原因
    • getMessage()方法,只显示产生异常的原因,但不显示类名。
    • printStackTrace()方法,用来跟踪异常事件发生时堆栈的内容。

    如果异常类之间有继承关系,在顺序安排上需注意。越是顶层的类,越放在下面,再不然就直接把多余的catch省略掉。 也就是先捕获子类异常再捕获父类异常。

  • finally:不管是否发生了异常,都必须要执行

    • 即使try和catch块中存在return语句,finally语句也会执行。是在执行完finally语句后再通过return退出。
    • finally语句块只有一种情况是不会执行的,那就是在执行finally之前遇到了System.exit(0)结束程序运行。

典型示例:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test8 {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("d:/a.txt");
            char c = (char) reader.read();
            char c2 = (char) reader.read();
            System.out.println("" + c + c2);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

声明异常

当CheckedException产生时,不一定立刻处理它,可以再把异常throws出去。

  • 如果一个方法中可能产生某种异常,但是并不能确定如何处理这种异常,则应根据异常规范在方法的首部声明该方法可能抛出的异常。
  • 如果一个方法抛出多个已检查异常,就必须在方法的首部列出所有的异常,之间以逗号隔开。

典型示例:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
 
public class Test9 {
    public static void main(String[] args) {
        try {
            readFile("joke.txt");
        } catch (FileNotFoundException e) {
            System.out.println("所需文件不存在!");
        } catch (IOException e) {
            System.out.println("文件读写错误!");
        }
    }  
    public static void readFile(String fileName) throws FileNotFoundException,          
    IOException {
        FileReader in = new FileReader(fileName);
        int tem = 0;
        try {
            tem = in.read();
            while (tem != -1) {
                System.out.print((char) tem);
                tem = in.read();
            }
        } finally {
            in.close();
        }
    }
}

自定义异常

自定义异常类只需要继承Exception类或RuntimeException类

  • 继承Exception类,则为受检查异常,必须对其进行处理。
  • 继承运行时异常RuntimeException类,则可以不处理。

习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器。

示例:

/**IllegalAgeException:非法年龄异常,继承Exception类*/
class IllegalAgeException extends Exception {
    //默认构造器
    public IllegalAgeException() {
     
    }
    //带有详细信息的构造器,信息存储在message中
    public IllegalAgeException(String message) {
        super(message);
    }
}
class Person {
    private String name;
    private int age;
 
    public void setName(String name) {
        this.name = name;
    }
 
    public void setAge(int age) throws IllegalAgeException {
        if (age < 0) {
            throw new IllegalAgeException("人的年龄不应该为负数");
        }
        this.age = age;
    }
 
    public String toString() {
        return "name is " + name + " and age is " + age;
    }
}
 
public class TestMyException {
    public static void main(String[] args) {
        Person p = new Person();
        try {
            p.setName("Lincoln");
            p.setAge(-1);
        } catch (IllegalAgeException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        System.out.println(p);
    }
}

使用异常机制的建议

  • 要避免使用异常处理代替错误处理,这样会降低程序的清晰性,并且效率低下。
  • 处理异常不可以代替简单测试---只在异常情况下使用异常机制。
  • 不要进行小粒度的异常处理---应该将整个任务包装在一个try语句块中。
  • 异常往往在高层处理。

try-with-resource

在处理流、文件等系统资源时,要在finally中写大量关闭语句,甚至关闭资源的代码竟然比业务代码还要多。为了解决这个问题在Java 1.7中新增的try-with-resource语法糖来打开资源。用法如下:

try (创建流对象语句,如果多个,使用';'隔开) {
    // 读写数据
} catch (IOException e) {
    e.printStackTrace();
}

示例可参见转换流那部分 。

posted @   AncilunKiang  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示