Java——异常

简介: 在 Java 中,程序执行过程中的不正常行为被称为异常。异常分为 Error 和 Exception。Error 表示系统级错误,而 Exception 则封装程序可能出现的问题。异常包括编译时异常和运行时异常(如数组越界)。异常可用于查找 bug 信息和作为方法内部的特殊返回值。处理异常的方式有默认处理和捕获异常,后者通过 try-catch 结构实现。此外,还可以自定义异常类来更灵活地处理特定情况。

认识异常

在Java中,将程序执行过程中发生的不正常行为称为异常

异常的种类

Error代表的是系统级别的错误,属于严重的问题
Exception叫做异常,代表程序可能出现的问题,通常用Exception和它的子类来封装程序所出现的问题
运行时异常: RuntimeException及其子类,编译阶段不会出现问题,运行时出现异常(例如数组越界异常)

编译时异常: 编译阶段就会出现异常提醒
例如之前写的克隆接口练习,出现的异常就属于编译时异常,编译阶段必须手动进行处理,

异常的作用

1.用来查询bug信息

通过异常的类型我们可以很快的发现程序的错误类型
当运行以下代码时:

class Student{
    private String name;
    private int age;
    public Student(String str){
        String[] strs = str.split("-");
        this.name = strs[0];
        this.age = Integer.parseInt(strs[1]);
    }
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Text {
    public static void main(String[] args) {
        Student student1 = new Student("张三,20");
        System.out.println(student1);
    }
}


出现了数组越界的异常,通过这些可以定位到出现异常的位置

String[] strs = str.split("-");//应该改为用","分割

2.可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况

例如当需要获取一个10~20的数字时,如果直接把不符合要求的情况打印在控制台上,这样调用处就无法得到具体的数是什么

此时就可以通过返回异常来解决:

异常的处理方式

JVM默认的处理方式

把异常的名称,异常的原因及出现的位置等信息输出在控制台
程序停止,下面的代码不会被执行

System.out.println("哈哈");
System.out.println(2/0);//出现异常
System.out.println("呵呵");

异常后面的内容并没有被执行

捕获异常

格式:
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}

public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        try {
            System.out.println(arr[5]);/*此处出现了异常,程序在这里就会创建一个 ArrayIndexOutOfBoundsException对象
                                         用这个对象和catch里面比较,看括号中的变量是否可以接收这个对象
                                         如果能接收,就表示异常被捕获,接着执行catch里面的代码
                                         之后再执行catch下面的代码*/
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("数组越界异常");
        }
        System.out.println("程序继续执行");
    }

通过捕获异常的方式处理,后续的代码是可以正常执行的

如果try中没有遇到问题,就会把try里的代码全部执行一遍,catch里面的代码并不会被执行

finally

try {
// 尝试执行的代码块
// 如果这里发生异常,则控制流会立即跳转到相应的catch块
} catch (ExceptionType1 e) {
// 处理ExceptionType1类型的异常的代码块
} finally {
// 无论是否发生异常,都会执行的代码块
// 通常用于执行清理操作,如关闭文件、数据库连接等
}

finally块里的语句,无论是否发生异常,都会执行,使用finally块的一个常见场景是确保资源(如文件句柄、网络连接或数据库连接)在使用后被正确关闭。即使发生异常,这些资源也需要在程序继续之前被释放。通过使用finally块,可以确保无论是否发生异常,这些资源都会被正确管理。

所以,对于这个方法,最终的返回值是finally里的2

多个异常的处理

当同时存在多个异常的时候,就要写多个catch与之对应

public static void main(String[] args) {
        try {
            String str = null;
            str.split("");
            System.out.println(2/0);
        }catch (NullPointerException e){
            System.out.println("空指针异常");
        }catch (ArithmeticException e){
            System.out.println("算术异常");
        }
        System.out.println("程序继续执行");
    }

注意: 如果异常中存在继承关系,子类要写在父类之前,不然所有的异常都会被父类捕获,程序报错

把父类写在最下面就可以了:

如果try中遇到的问题没有被捕获,最终还是会交给虚拟机处理


之后就会用虚拟机默认的处理方式,打印在控制台上:

如果try中出现的问题被捕捉到了,那么出现问题的下面就不会继续被执行

try {
            System.out.println(arr[10]);
            System.out.println("这里之后不会执行");
            System.out.println(2/0);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界异常");
        } catch (NullPointerException e) {
            System.out.println("空指针异常");
        } catch (ArithmeticException e) {
            System.out.println("算术异常");
        }

所以后面的算术异常也不会被捕捉到

异常中的方法

通过快捷键ctrl + alt + t 可以快速生成 try-catch语句

public String getMessage(): 返回throwable的详细信息字符串

public String toString(): 返回此可抛出的简短描述

public void printStackTrace(): 把异常的错误信息输出在控制台上

printStackTrace方法打印的信息包含了getMessage()和toString()的信息,也最为常用

抛出异常

throws: 写在方法定义处,表示声明一个异常,告诉调用者,使用此方法可能会有哪些异常

public void方法名() throws 异常类名1,异常类名2{ ···· }
编译时异常:必须要写
运行时异常:可以不写

throw: 写在方法内,表示结束方法,用来手动抛出异常对象,交给调用者处理,方法中下面的代码不再执行

public void 方法(){
throw new 异常对象();
}

区别:
throwthrow关键字用于在方法中抛出一个异常,throws关键字用于声明一个方法可能会抛出的异常,本身并不抛出异常,它只是一个声明,告诉方法的调用者这个方法在执行过程中可能会抛出哪些异常

自定义异常

创建自定义异常类:
声明一个继承自Exception类或其子类的类,作为自定义异常类。
根据需要添加构造方法和其他方法。例如,可以添加一个带有错误消息的构造方法,以便在抛出异常时提供有关异常的详细信息。

当直接继承Exception类来创建自定义异常时,创建的是一个受检异常。受检异常是那些必须在方法签名中使用throws关键字声明,并且在调用该方法的地方使用try-catch块捕获或继续向上抛出的异常。编译器会强制要求这样做,以确保处理了所有可能的异常情况

public class MyCustomException extends Exception {  
  
    public MyCustomException() {  
        super();  
    }  
  
    // 带字符串消息的构造函数  
    public MyCustomException(String message) {  
        super(message);  
    }  
    
}

继承RuntimeException类,表示的是运行时发生的异常。RuntimeException和其子类被视为未受检异常。未受检异常不需要在方法签名中声明,编译器也不会强制要求你捕获它们。

public class PassWordException extends RuntimeException{
    public PassWordException() {
    }
    public PassWordException(String message) {
        super(message);
    }
}

之后的使用方法和Java中的异常是一样的,这里给出一个登录系统的示例:

public class Login {
    private String username;
    private String password;
    public Login() {
    }
    public Login(String username, String password) {
        this.username = username;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void Loginfo(String username,String password)throws UserNameException,PassWordException{
        if(!this.username.equals(username)){
            throw new UserNameException("用户名不存在");
        }
        if(!this.password.equals(password)){
            throw new PassWordException("密码错误");
        }
        System.out.println("登录成功");
    }
    public static void main(String[] args) {
        Login login = new Login();
        while (true) {
            try {
                System.out.println("请输入用户名");
                String username = new Scanner(System.in).nextLine();
                login.setUsername(username);
                System.out.println("请输入密码");
                String password = new Scanner(System.in).nextLine();
                login.setPassword(password);
                login.Loginfo("admin","123");
                break;
            } catch (UserNameException e) {
                e.printStackTrace();
            } catch (PassWordException e) {
                e.printStackTrace();
            }
        }
    }
}
相关文章
|
8天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
8天前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
|
9天前
|
IDE 前端开发 Java
怎样避免 Java 中的 NoSuchFieldError 异常
在Java中避免NoSuchFieldError异常的关键在于确保类路径下没有不同版本的类文件冲突,避免反射时使用不存在的字段,以及确保所有依赖库版本兼容。编译和运行时使用的类版本应保持一致。
|
10天前
|
Java 编译器
如何避免在 Java 中出现 NoSuchElementException 异常
在Java中,`NoSuchElementException`通常发生在使用迭代器、枚举或流等遍历集合时,尝试访问不存在的元素。为了避免该异常,可以在访问前检查是否有下一个元素(如使用`hasNext()`方法),或者使用`Optional`类处理可能为空的情况。正确管理集合边界和条件判断是关键。
|
13天前
|
Java
Java异常捕捉处理和错误处理
Java异常捕捉处理和错误处理
14 1
|
15天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
33 2
|
22天前
|
Java
如何在 Java 中处理“Broken Pipe”异常
在Java中处理“Broken Pipe”异常,通常发生在网络通信中,如Socket编程时。该异常表示写入操作的另一端已关闭连接。解决方法包括:检查网络连接、设置超时、使用try-catch捕获异常并进行重试或关闭资源。
|
24天前
|
存储 安全 Java
如何避免 Java 中的“ArrayStoreException”异常
在Java中,ArrayStoreException异常通常发生在尝试将不兼容的对象存储到泛型数组中时。为了避免这种异常,确保在操作数组时遵循以下几点:1. 使用泛型确保类型安全;2. 避免生类型(raw types)的使用;3. 在添加元素前进行类型检查。通过这些方法,可以有效防止 ArrayStoreException 的发生。
|
25天前
|
人工智能 Oracle Java
解决 Java 打印日志吞异常堆栈的问题
前几天有同学找我查一个空指针问题,Java 打印日志时,异常堆栈信息被吞了,导致定位不到出问题的地方。
32 2
|
29天前
|
Java 索引
如何避免在 Java 中引发`StringIndexOutOfBoundsException`异常
在Java中,处理字符串时若访问了不存在的索引,会抛出`StringIndexOutOfBoundsException`异常。为避免此异常,应确保索引值在有效范围内,例如使用`length()`方法检查字符串长度,并确保索引值不小于0且不大于字符串长度减1。