java:Java中的异常处理

目录

异常的概念与体系结构

异常的概念:

异常的体系结构:

异常的处理方式

防御式编程:

异常的抛出:

异常的捕获:

finally:

代码示例:

异常的处理流程

自定义异常类

举例: 


异常的概念与体系结构

异常的概念:

在程序中不正常行为称为异常,如算术异常、数组越界异常、空指针异常等。

例如:

public class ExceptionDemo {

    public static void main(String[] args) {
        // 示例算术异常
        try {
            int result = 10 / 0; // 除以0会抛出算术异常
        } catch (ArithmeticException e) {
            System.out.println("算术异常:" + e.getMessage());
        }

        // 示例数组越界异常
        try {
            int[] arr = {1, 2, 3};
            System.out.println(arr[100]); // 访问数组越界会抛出数组越界异常
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界异常:" + e.getMessage());
        }

        // 示例空指针异常
        try {
            String str = null;
            System.out.println(str.length()); // 对空指针调用方法会抛出空指针异常
        } catch (NullPointerException e) {
            System.out.println("空指针异常:" + e.getMessage());
        }
    }
}

异常的体系结构:

        Throwable是异常体系的顶层类,派生出Error和Exception两个重要的子类,分为编译时异常和运行时异常。


异常的处理方式

防御式编程:

LBYL(Look Before You Leap):在操作之前进行充分的检查,事前防御型。例如,在代码中先检查条件,再执行操作,以避免异常情况的发生。

EAFP(It's Easier to Ask Forgiveness than Permission):先操作,遇到问题再处理,事后认错型。这种方式更关注正常流程,代码更清晰,容易理解。

异常的抛出:

使用throw关键字抛出异常对象,将错误信息告知给调用者。抛出的异常对象必须是Exception或其子类对象,根据异常类型不同,处理方式也不同。

异常的捕获:

通过try-catch捕获并处理异常,可以在catch块中对捕获到的异常进行具体处理。如果异常无法在当前方法中处理,可以继续向上抛出或交给调用者处理。

异常声明throws:在方法声明时使用throws关键字将异常抛给方法的调用者处理,提醒调用者处理异常。

finally:

finally块用于资源清理的扫尾工作,无论是否发生异常,finally中的代码都会被执行一般用于释放资源,确保资源得到正确释放。

代码示例:

public class ExceptionHandlingDemo {

    public static void main(String[] args) {
        // 防御式编程示例 - LBYL
        String str = null;
        if (str != null) {
            System.out.println(str.length()); // 不会执行,避免空指针异常
        }

        // 防御式编程示例 - EAFP
        int[] arr = {1, 2, 3};
        try {
            System.out.println(arr[100]); // 尝试访问数组越界
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界异常:" + e.getMessage());
        }

        // 异常的抛出示例
        try {
            validateAge(-5); // 抛出自定义异常
        } catch (IllegalArgumentException e) {
            System.out.println("年龄不能为负数:" + e.getMessage());
        }

        // 异常的捕获示例
        try {
            int result = divide(10, 0); // 抛出算术异常
        } catch (ArithmeticException e) {
            System.out.println("算术异常:" + e.getMessage());
        }

        // finally示例
        try {
            System.out.println("Try block");
        } finally {
            System.out.println("Finally block - resource cleanup");
        }
    }

    // 自定义异常类
    static void validateAge(int age) {
        if (age < 0) {
            throw new IllegalArgumentException("年龄不能为负数");
        }
    }

    // 抛出算术异常
    static int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("除数不能为0");
        }
        return a / b;
    }
}

在上述代码中,演示了防御式编程中的LBYL和EAFP方式,异常的抛出和捕获,以及finally块的使用。通过这些示例,展示了不同的异常处理方式在实际代码中的应用。


异常的处理流程

  • 程序首先执行try中的代码块
  • 如果try中的代码块出现异常,程序会立即跳转到对应的catch块进行异常处理
  • 如果找到匹配的异常类型,就会执行对应的catch块中的代码
  • 如果没有找到匹配的异常类型,异常会被向上抛出,继续传递给上层调用者
  • 无论是否找到匹配的异常类型,finally块中的代码都会被执行,用于进行资源清理等操作。
  • 如果异常一直向上传递到main方法仍未被处理,最终会交给JVM处理,导致程序异常终止。

下面是一个示例代码,演示了完整的异常处理流程:

public class ExceptionHandlingFlow {  

    public static void main(String[] args) {
        try {
            int result = divide(10, 0); // 抛出算术异常
        } catch (ArithmeticException e) {
            System.out.println("算术异常:" + e.getMessage());
            // 继续向上抛出异常
            throw e;
        } finally {
            System.out.println("finally块中的代码一定会执行");
        }
    }

    // 抛出算术异常
    static int divide(int a, int b) {
        try {
            if (b == 0) {
                throw new ArithmeticException("除数不能为0");
            }
            return a / b;
        } catch (ArithmeticException e) {
            System.out.println("捕获到算术异常:" + e.getMessage());
            // 继续向上抛出异常
            throw e;
        } finally {
            System.out.println("divide方法的finally块中的代码一定会执行");
        }
    }
}

运行结果:

在上述代码中,通过try-catch-finally块展示了完整的异常处理流程。无论是否出现异常,finally块中的代码都会被执行,用于进行必要的资源清理操作。这样可以确保程序在异常情况下也能够正常运行并保持稳定性。


自定义异常类

  • 自定义异常类继承自Exception或RuntimeException,用于表示实际开发中遇到的特定异常。
  • 可以实现带有String类型参数的构造方法,用于说明异常的原因。
  • 自定义异常通常继承自Exception或RuntimeException,分为受查异常和非受查异常。

举例: 

// 自定义用户名异常类,继承自Exception,表示用户名错误
class UserNameException extends Exception {
    public UserNameException(String message) {
        super(message);
    }
}

// 自定义密码异常类,继承自Exception,表示密码错误
class PasswordException extends Exception {
    public PasswordException(String message) {
        super(message);
    }
}

public class CustomExceptionExample {

    // 模拟用户登录,抛出自定义异常
    public static void login(String userName, String password) throws UserNameException, PasswordException {
        if (!userName.equals("admin")) {
            throw new UserNameException("用户名错误");
        }
        if (!password.equals("123456")) {
            throw new PasswordException("密码错误");
        }
        System.out.println("登录成功");
    }

    public static void main(String[] args) {
        try {
            login("admin", "12345"); // 模拟登录,抛出异常
        } catch (UserNameException e) {
            System.out.println("用户名异常:" + e.getMessage());
            // 可以在此处处理用户名异常
        } catch (PasswordException e) {
            System.out.println("密码异常:" + e.getMessage());
            // 可以在此处处理密码异常
        }
    }
}

在上述代码中,我们定义了两个自定义异常类UserNameExceptionPasswordException,分别用于表示用户名错误和密码错误的异常。这些异常类继承自Exception,表示受查异常,需要在方法声明中进行处理或抛出。在login方法中模拟用户登录过程,如果用户名或密码错误,则抛出相应的自定义异常。在main方法中通过try-catch块捕获并处理这些自定义异常,确保程序在异常情况下能够正常运行。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蓝lanll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值