Java 异常相关(二):异常处理机制的补充,自定义异常的使用等

一、前言

记录时间 [2024-05-22]

前置文章:
Java 异常相关:异常体系结构,异常与错误的区别等

本文讲述 Java 异常相关知识,对异常处理机制进行补充,以及自定义异常的方式。


文章对异常知识的描述显然是笼统而简洁的,对于异常的学习,更应注重平时的积累和整理。


二、异常处理机制

Java 通过 try-catch-finally 语句块来捕获和处理异常。5 个处理机制关键字如下:

  • try - 用于包围可能会抛出异常的代码块。
  • catch - 紧跟在 try 块之后,用于捕获并处理特定类型的异常。
  • finally - 无论是否发生异常,都会执行的代码块,通常用于释放资源等善后工作
  • throw - 用于在代码中手动抛出一个异常实例。
  • throws - 用于声明方法可能抛出的异常类型,将异常处理的责任转移给方法的调用者。

1. try-catch-finally

语法

// try 和 catch 是必须的,finally 可以不要
// 可以在 finally 中关闭一些 IO、资源

try {
	// try 监控区域
} catch (ArithmeticException e) { 
    // catch 捕获异常
} finally { 
    // 处理善后工作
}

简单示例

以下是一个使用 try-catch-finally 语句处理异常的简单示例。

public static void main(String[] args) {
    int a = 1;
    int b = 0;

    // try 和 catch 是必须的,finally 可以不要
    // 可以在 finally 中关闭一些 IO、资源

    try { // try 监控区域
        System.out.println(a/b);
    } catch (ArithmeticException e) { // catch 捕获异常
        System.out.println("程序出现异常,变量 b 不能为 0");
    } finally { // 处理善后工作
        System.out.println("finally");
    }

}

使用 try-catch-finally 语句捕获一个被除数为 0 的异常:

  • 把需要监控的代码放在 try 区域;
  • 经由 catch 捕获异常后,我们可以做一些处理,比如输出问题;
  • 其中,catch 中的参数是想要捕获的异常类型,如 ArithmeticException
  • 最后,在 finally 中完成善后工作,无论异常是否被捕获,finally 最终都会执行。

错误 Error 也可以被捕获。

如果想要捕获多种异常,可以写多个 catch 语句块。

例如:

// 快捷键 Ctrl + Alt + T,快速生成代码块

try { // try 监控区域
    System.out.println(a/b);
} catch (ArithmeticException e) { // catch 捕获异常
    System.out.println("程序出现异常,变量 b 不能为 0");
} catch (Exception e) {
    System.out.println("Exception");
} catch (Throwable t) {
    System.out.println("Throwable");
} finally { // 处理善后工作
    System.out.println("finally");
}

需要注意的是,catch 语句块自上而下层层递进,范围大的异常或错误捕获需要写在下面


2. throw

在 Java 中,throw 关键字用于手动抛出一个异常。当需要在代码中表示某种异常情况发生时,就可以使用 throw 来创建并抛出一个异常对象。

这通常用于自定义异常处理逻辑,或者在方法内部检测到不符合条件的情况时主动抛出异常。

通过这种方式,可以根据程序的逻辑主动控制异常的抛出,使得异常处理更加灵活和精确。

语法

throw new ExceptionType("异常信息");

其中,ExceptionType 是用户希望抛出的异常类型,可以是具体的异常类名,如 IllegalArgumentExceptionNullPointerException 等,也可以是自定义的异常类。

紧跟在后面的字符串是可选的,用于提供异常的具体描述信息。

简单示例

假设我们有一个方法,该方法接收一个年龄参数,如果年龄小于 0,我们希望抛出一个 IllegalArgumentException 来表示非法参数。

public class ThrowExample {
    public static void main(String[] args) {
        try {
            checkAge(-1); // 这将抛出异常
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage()); // 打印异常信息
        }
    }

    // 检查年龄的方法
    public static void checkAge(int age) throws IllegalArgumentException {
        if (age < 0) {
            throw new IllegalArgumentException("年龄不能为负数");
        } else {
            System.out.println("年龄合法");
        }
    }
}

在这个例子中,checkAge 方法检查传入的年龄是否为负数。如果是,就通过 throw new IllegalArgumentException("年龄不能为负数") 抛出一个带有详细信息的 IllegalArgumentException

main 方法中,我们通过 try-catch 块捕获这个异常,并打印出异常信息。


3. throws

在 Java 中,throws 关键字用于声明方法可能抛出的异常类型,它告诉调用者这个方法执行时可能会遇到的问题,从而提醒调用者做出相应的异常处理。

使用 throws 关键字可以将异常处理的责任上交给方法的调用者。

通过 throws 声明异常,可以使代码更加清晰地表明哪些异常需要调用者关注并处理,有助于提高程序的可读性和健壮性。

语法

在方法签名后使用 throws 关键字,后面跟着可能抛出的一个或多个异常类型,用逗号分隔。

public returnType methodName() throws ExceptionType1, ExceptionType2 {
    // 方法体
}

简单示例

考虑一个读取文件并返回其内容的函数,这个操作可能会抛出 IOException

我们可以使用 throws 来声明这个方法可能抛出的异常:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ThrowsExample {

    public static void main(String[] args) {
        try {
            String content = readFileContent("example.txt");
            System.out.println(content);
        } catch (IOException e) {
            System.out.println("读取文件时发生错误:" + e.getMessage());
        }
    }

    // 声明可能抛出 IOException 的方法
    public static String readFileContent(String filePath) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        StringBuilder content = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            content.append(line).append("\n");
        }
        reader.close();
        return content.toString();
    }
}

在这个例子中,readFileContent 方法可能抛出 IOException,因为它涉及到文件读取操作。

因此,我们在方法签名中使用 throws IOException 来声明这一可能性。

main 方法中调用 readFileContent 时,我们通过 try-catch 块来捕获并处理这个可能发生的异常。


三、自定义异常

使用 Java 内置的异常类可以描述在编程时出现的大部分异常情况。但是,在 Java 中,可能需要根据特定的业务逻辑或应用需求定义自己的异常类,这就是自定义异常。

自定义异常通常继承自 Exception 类或其子类(对于运行时异常,则继承自 RuntimeException)。

自定义异常增强了程序的清晰度和可维护性,使得异常处理更贴近应用程序的具体逻辑。

下面是如何创建和使用自定义异常的简单步骤和示例。


1. 步骤

在程序中使用自定义异常类,大体可分为以下几个步骤:

  • 定义异常类 - 新建一个类,继承自 Exception 或其子类(如 IOExceptionRuntimeException 等),根据异常的性质选择合适的基类。
  • 构造方法 - 至少定义一个构造方法,通常接受一个字符串参数(异常消息),并调用超类的构造方法传递这个消息。
  • 捕获并处理异常
    • 在需要抛出自定义异常的地方,使用 throw new YourException("异常信息") 来抛出异常;
    • 如果在当前抛出异常的方法中处理异常,可以使用 try-catch 语句捕获并处理;
    • 否则在方法的声明处通过 throws 关键字指明要抛出给方法调用者的异常。

2. 示例

假设我们要为一个学生管理系统定义一个特定的异常,当尝试注册一个已经存在的学生 ID 时抛出。

我们可以创建一个 StudentAlreadyExistsException,让这个类继承 Exception 为父类,它就变成了一个自定义异常类,处理特定的异常。

// 自定义异常类
public class StudentAlreadyExistsException extends Exception {
    
    public StudentAlreadyExistsException(String message) {
        // 调用Exception的构造方法传递异常信息
        super(message); 
    }
    
}

然后,我们在其他方法中,使用这个自定义异常类处理一些特定的异常。

// 使用自定义异常的类
public class StudentManager {
    private List<Student> students = new ArrayList<>();

    public void registerStudent(Student student) throws StudentAlreadyExistsException {
        for (Student s : students) {
            if (s.getId().equals(student.getId())) {
                // 主动抛出异常给上述自定义异常类
                throw new StudentAlreadyExistsException("学生 ID 已存在,无法注册。");
            }
        }
        students.add(student);
        System.out.println("学生注册成功。");
    }

    public static void main(String[] args) {
        StudentManager manager = new StudentManager();
        Student student = new Student("S001", "张三");

        try {
            manager.registerStudent(student);
            manager.registerStudent(student); // 尝试再次注册相同的 ID
        } catch (StudentAlreadyExistsException e) {
            System.out.println(e.getMessage());
        }
    }
}

在这个示例中:

  • 我们首先定义了一个 StudentAlreadyExistsException 类,它继承自 Exception
  • 然后,在 StudentManager 类的 registerStudent 方法中,当我们检测到尝试注册的学生 ID 已存在时,就抛出这个自定义异常。
  • main 方法中,我们通过 try-catch 块捕获并处理这个异常。

四、总结

本文讲述 Java 异常相关知识,对异常处理机制进行补充,以及自定义异常的方式。

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

一些参考资料

狂神说 Java 零基础:https://www.bilibili.com/video/BV12J41137hu/
TIOBE 编程语言走势: https://www.tiobe.com/tiobe-index/
Typora 官网:https://www.typoraio.cn/
Oracle 官网:https://www.oracle.com/
Notepad++ 下载地址:https://notepad-plus.en.softonic.com/
IDEA 官网:https://www.jetbrains.com.cn/idea/
Java 开发手册:https://developer.aliyun.com/ebook/394
Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/

  • 37
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,下面是回复: 这一关的任务是学习如何使用Java中的自定义异常来判断用户名是否符合规范。在实际开发中,我们经常需要对用户输入的数据进行验证,以确保数据的正确性和安全性。而自定义异常可以帮助我们更好地处理这些验证过程中可能出现的异常情况,提高程序的健壮性和可靠性。在本关中,我们需要实现一个自定义异常类,用于判断用户名是否符合规范,如果不符合规范,则抛出异常并提示用户重新输入。这样可以避免用户输入不合法的用户名,从而提高系统的安全性和可靠性。 ### 回答2: 在学习Java异常处理时,我们需要了解并掌握自定义异常的方法。自定义异常可以让我们更好地控制程序的运行,提高代码的可读性和可维护性。在本题中,我们需要自定义一个异常类,用于判断用户名是否合法。 首先,我们需要了解在Java中创建自定义异常的步骤。首先,我们需要创建一个继承自Exception或RuntimeException的类,该类的构造方法中传递一个String类型的参数,用于输出异常信息。然后,我们需要在程序中抛出该异常,即使用throw语句来抛出该异常。 在本题中,我们需要判断用户名是否合法,如果不合法,则抛出自定义异常。我们可以定义一个名为UsernameException的类,该类继承自Exception或RuntimeException,并添加一个构造方法,将错误信息作为参数传递给父类。例如: public class UsernameException extends Exception{ public UsernameException(String message){ super(message); } } 在判断用户名时,我们需要检查用户名是否符合规范,如长度是否在6到18个字符之间,是否只包含字母和数字等。如果用户名不符合规范,则可以使用throw语句抛出自定义异常,如下所示: public void checkUsername(String username) throws UsernameException{ if(username.length() < 6 || username.length() > 18){ throw new UsernameException("用户名长度应在6到18个字符之间"); } //其他判断 } 在该方法中,如果检查发现用户名不符合要求,则抛出自定义异常,并将错误信息传递给父类。如果用户名符合规范,则可以继续执行后续代码。 总之,自定义异常可以让我们更好地控制程序的运行,提高代码的可读性和可维护性。在本题中,我们需要自定义一个用于判断用户名是否合法的异常类,可以帮助我们更好地进行异常处理,确保程序的稳定性和正确性。 ### 回答3: 在Java中,异常处理是一个非常重要的知识点,它可以帮助我们更好地处理程序中出现的错误,并且提高程序的健壮性。而自定义异常则是异常处理的重要组成部分之一,它可以让我们自己定义一些异常类型,并在需要的时候抛出这些异常。 在第一关中,我们要实现一个判断用户名是否符合规范的功能,如果不符合规范,则需要抛出一个自定义异常。具体的实现步骤如下: 1. 首先,我们需要定义一个叫做NameException的自定义异常类,它继承自Exception类。在这个自定义异常类中,我们可以定义一些构造函数,来传入异常信息以及异常的原因等等。 2. 接下来,我们要定义一个叫做checkName的方法,来判断用户名是否符合规范。如果不符合规范,则需要抛出我们在上一步中定义的NameException异常。 3. 在checkName方法中,我们需要对用户名进行一些判断,例如,是否为空、长度是否符合要求、是否包含特殊字符等等。如果有不符合规范的地方,就要new一个NameException对象,并将异常信息传入该对象中。 4. 在外层调用checkName方法时,需要使用try-catch语句来捕获可能抛出的NameException异常。如果出现了该异常,则需要打印异常信息。 通过以上步骤的实现,就可以完成判断用户名是否符合规范的任务,并且在用户名不符合规范的时候抛出一个自定义异常。这样就能让我们更好地处理程序中出现的异常情况,提高程序的健壮性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值