JAVA入坑之异常处理

文章详细介绍了Java中的程序错误类型,包括编译时错误、运行时错误和逻辑错误。接着,讨论了异常的概念,异常的产生原因,并展示了Java异常的层次结构,区分了受检异常和非受检异常。文章还深入讲解了Java的异常处理机制,包括try-catch-finally语句块、throw和throws关键字的使用,以及try-with-resources语句。最后提到了自定义异常的创建方法。
摘要由CSDN通过智能技术生成

目录

一、程序错误

二、异常

2.1概述

2.2产生原因

2.3Java 异常层次结构

Error

Exception

2.3.1非受检异常

2.3.2受检异常

 三、异常处理机制

3.1概述

​编辑

调用栈Call Stack

3.2异常类型的实现

3.3异常处理的关键字:

3.3.1try-catch Block

​编辑

补充块变量的作用范围

补充Try-catch的执行顺序

3.3.2Throwable 类常用方法

3.3.3finally 块

3.3.4try-with-resources语句

3.3.5 throw和throws 关键字

3.3.6自定义异常


一、程序错误

在Java程序中,错误通常分为三类:编译时错误、运行时错误和逻辑错误。

1.编译时错误:编译时错误是指在编译Java程序时发生的错误。这些错误通常是由于语法错误或类型不匹配等问题导致的。例如,下面的代码将无法通过编译,因为它试图将一个字符串赋值给一个整型变量:

int x = "hello"; // 编译时错误

2.运行时错误:运行时错误是指在程序运行过程中发生的错误。这些错误通常是由于程序中的异常情况导致的,例如除以零、空指针引用等。运行时错误会导致程序崩溃并抛出异常。例如,下面的代码将在运行时抛出ArithmeticException异常,因为它试图除以零:

int x = 10 / 0; // 运行时错误,抛出ArithmeticException异常

3.逻辑错误:逻辑错误是指程序虽然能够正常编译和运行,但是其行为与预期不符。这些错误通常是由于程序员在编写代码时犯了逻辑错误导致的。例如,下面的代码本意是计算两个数的平均值,但由于程序员犯了一个简单的逻辑错误,导致结果不正确:

int x = 10;
int y = 20;
int average = x + y / 2; // 逻辑错误,应该写成 (x + y) / 2

二、异常

2.1概述

异常是程序执行期间发生的意外事件。它影响程序指令流,从而导致程序异常终止。

2.2产生原因

  • 无效的用户输入
  • 设备故障
  • 网络连接丢失
  • 物理限制(磁盘内存不足)
  • 代码错误
  • 打开一个不可用的文件

2.3Java 异常层次结构

0ac8bc6b33944b01b822a6e0a987e8a0.jpg

 从上图可以看到,Throwable类是层次结构中的根类。

请注意,层次结构分为两个分支:错误(Error)和异常(Exception)。

Error

Error表示不可恢复的情况,例如Java虚拟机(JVM)内存不足,内存泄漏,堆栈溢出错误,库不兼容,无限递归等。

错误通常是程序员无法控制的,我们不应该尝试处理错误。

出现严重的,无法恢复运行状态的错误,出现错误后一般只能进行详细的日志记录汇报

Exception

程序可以捕获并处理异常。

当方法内发生异常时,它将创建一个对象。该对象称为异常对象。

它包含有关异常的信息,例如异常的名称和说明以及发生异常时的程序状态。例如空指针访问 试图读取不存在的文件 网络连接中断

分类:受检(编译时)异常和非受检(运行时)异常

2.3.1非受检异常

非受检异常(运行时异常) 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。 对于这类异常,可以不作处理或者加上逻辑判断

运行中不应该出现而又出现的问题,此类异常一般是由于代码(逻辑)错误(不严谨)产生的,不应通过捕获异常处理,而应通过修正代码更正错误解决

2.3.2受检异常

是指要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求java程序必须捕获或声明所有编译时异常。 对于这类异常,如果程序不处理,可能会带来意想不到的结果。

一般为程序与程序控制之外的外部资源互交时,产生的错误 如文件无法读取,数据库无法访问,网络无法连接等 程序必须为可能出现的受检异常,提供异常处理程序,从而使程序可以继续运行而非停止崩溃

2.3.3常用异常:

 三、异常处理机制

3.1概述

异常处理机制是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况,即超出程序正常执行流程的某些特殊条件。它让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。

调用栈Call Stack

调用栈(Call Stack)是计算机内部一种用来跟踪程序运行状态的数据结构,类似于人们在日常生活中的“记事本”,记录了程序在运行过程中每一个函数调用的位置、参数和返回值等信息。它是计算机科学中存储有关正在运行的子程序的消息的栈

3.2异常类型的实现

 Java提供了3种主要的异常类型的实现

  1. java.lang.Error,继承自Throwable,
  2. 非受检 java.lang.Exception,继承自Throwable,受检异常
  3. java.lang.RuntimeException ,继承自Exception,运行时异常,非受检异常

java.lang.Throwable类,所有错误/异常的超类,仅Throwable及其子类对象可以被catch语句捕获

3.3异常处理的关键字:

异常处理的关键字:

捕获异常:

  1. try:执行可能产生异常的代码;
  2. catch:捕获异常;
  3. finally:无论是否发生异常,代码总被执行;

抛出异常:

  1. throw:异常生成阶段,手动抛出异常对象;

声明异常:

  1. throws声明方法可能要抛出的各种异常类

3.3.1try-catch Block

public class Example {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        try {
            // 尝试访问数组中不存在的元素
            System.out.println(numbers[3]);
            // 尝试将整数除以零
            System.out.println(3 / 0);
        } catch (ArrayIndexOutOfBoundsException e) {
            // 捕获并处理数组越界异常
            System.out.println("数组越界!");
        } catch (ArithmeticException e) {
            // 捕获并处理算术异常
            System.out.println("算术异常!");
        }
    }
}

将多个可能引发异常的代码 置于一个try块中 顺次声明多个catch与之关联

在try代码块与catch代码块之间,禁止定义其他代码

补充块变量的作用范围

块变量(也称为局部变量)是在代码块(如方法、循环或条件语句)中定义的变量。它们的作用范围仅限于定义它们的代码块。当代码块执行完毕后,块变量将不再可用。

public class Example {
    public static void main(String[] args) {
        // 定义一个块变量
        int x = 10;
        if (x > 5) {
            // 定义另一个块变量
            int y = 20;
            System.out.println("x: " + x + ", y: " + y);
        }
        // 这里无法访问块变量 y,因为它已经超出了作用范围
        System.out.println("x: " + x);
    }
}

补充Try-catch的执行顺序

3.3.2Throwable 类常用方法

Throwable 类是 Java 语言中所有错误或异常的超类。它包含了一些常用的方法,可以帮助我们获取有关异常的信息,以下是一些常用的方法:

  • getMessage():返回此 throwable 的详细消息字符串。
  • printStackTrace():将此 throwable 及其追踪输出至标准错误流。这个方法会打印出异常的类型、详细消息以及异常发生时的堆栈信息。
  • toString():返回此 throwable 的简短描述。这个方法返回的字符串包含了异常的类型和详细消息。
  • getCause():返回此 throwable 的原因。如果原因不存在或未知,则返回 null。
public class Example {
    public static void main(String[] args) {
        try {
            // 尝试将整数除以零
            System.out.println(3 / 0);
        } catch (ArithmeticException e) {
            // 获取并打印异常信息
            System.out.println("异常类型: " + e);
            System.out.println("异常信息: " + e.getMessage());
            System.out.println("堆栈信息: ");
            e.printStackTrace();
            System.out.println("原因: " + e.getCause());
        }
    }
}

3.3.3finally 块

finally 块是与 try-catch 语句一起使用的一个可选代码块。它包含的代码无论是否发生异常都会被执行。通常,我们在 finally 块中放置一些清理资源的代码,例如关闭文件、释放内存等。

public class Example {
    public static void main(String[] args) {
        try {
            // 尝试将整数除以零
            System.out.println(3 / 0);
        } catch (ArithmeticException e) {
            // 捕获并处理算术异常
            System.out.println("算术异常!");
        } finally {
            // 无论是否发生异常,都会执行这里的代码
            System.out.println("清理资源...");
        }
    }
}

Try-catch-finally,执行顺序

包含return语句时,try-catch-finally的执行顺序 

总结

Finally块仅用于释放资源,禁止参与业务逻辑的处理,块内禁止使用return语句

3.3.4try-with-resources语句

 try-with-resources语句是Java 7中引入的一种try语句,旨在减轻开发人员释放try块中使用的资源的义务。它的全部想法是,开发人员无需担心仅在一个try-catch-finally块中使用的资源的资源管理。这是通过消除对finally块的需要而实现的,实际上,开发人员仅在关闭资源时才使用块。此外,使用try-with-resources的代码通常更清晰易读,因此使代码更易于管理,尤其是当我们处理许多try块时

static String readFirstLineFromFile(String path) throws IOException {
    // try-with-resources语句,声明了两个资源:FileReader和BufferedReader
    try (FileReader fr = new FileReader(path);
         BufferedReader br = new BufferedReader(fr)) {
        // 从文件中读取第一行
        return br.readLine();
    }
    // 在try块结束后,资源会被自动关闭
}

在这个例子中,声明在try-with-resources语句中的资源是一个FileReader和一个BufferedReader。这些资源的声明语句出现在紧跟在try关键字后面的括号内。在Java SE 7及更高版本中,类FileReaderBufferedReader实现了接口java.lang.AutoCloseable。由于在一个带有资源的try语句中声明了FileReader和BufferedReader实例,因此无论try语句是正常完成还是突然完成(由于方法BufferedReader.readLine抛出IOException),它们都将被关闭。

3.3.5 throw和throws 关键字

当方法没有捕获到可能发生的受检异常时,方法必须指定抛出受检异常 通过在方法声明添加throws子句,实现在方法抛出异常;在方法参数列表后(),方法体前{};方法抛出的所有异常使用“,”逗号分隔;

throwthrows是两个不同的关键字,它们都与异常处理有关。

throws关键字用于方法声明,用来指定该方法可能抛出的异常类型。它表示出现异常的一种可能性,但并不一定会发生这些异常。例如:

public void myMethod() throws IOException {
    // 方法体
}

throw关键字用于方法体内,用来显式地抛出一个异常对象。执行throw则一定抛出了某种异常对象。例如:

public void myMethod() {
    // ...
    throw new IOException("发生了IO异常");
}

Java throws 和throw关键字

import java.io.IOException;

public class ThrowsExample {
    public static void main(String[] args) {
        try {
            myMethod();
        } catch (IOException e) {
            // 处理异常
            System.out.println("捕获到了异常: " + e.getMessage());
        }
    }

    public static void myMethod() throws IOException {
        // 方法体
        // 如果在方法体中发生了IO异常,可以抛出
        throw new IOException("发生了IO异常");
    }
}

简单来说,throws关键字用于声明一个方法可能抛出的所有异常信息,而throw则是指抛出的一个具体的异常类型。

注意

3.3.6自定义异常

 在Java中,除了可以使用系统提供的异常类之外,还可以自定义异常类。自定义异常类通常用来表示程序中特定的异常情况。

public class CustomExceptionExample {
    public static void main(String[] args) {
        int score = -5;
        try {
            if (score < 0 || score > 100) {
                throw new InvalidScoreException("分数值无效: " + score);
            }
            System.out.println("分数值有效: " + score);
        } catch (InvalidScoreException e) {
            // 处理异常
            System.out.println(e.getMessage());
        }
    }
}

class InvalidScoreException extends Exception {
    public InvalidScoreException(String message) {
        super(message);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

烟雨平生9527

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

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

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

打赏作者

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

抵扣说明:

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

余额充值