百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

三十七、Java异常处理

lipiwang 2024-12-01 00:42 5 浏览 0 评论

在Java编程中,异常处理是一项至关重要的技能,让我们能够有效地应对程序运行过程中可能出现的各种错误状况,从而使程序更具健壮性。

什么是异常?

Java异常程序运行时出现的问题或错误的表示,代表了程序正常的控制流程被中断的情况。Java将异常分为两大类:checked异常unchecked异常(也称运行时异常)。

分类

描述

Checked Exception

在编译阶段就需要程序员处理,如果不处理或声明抛出,编译器将拒绝编译。例如,当你试图打开一个不存在的文件时,Java会抛出 java.io.FileNotFoundException ,这是一种checked异常。

Unchecked Exception

在运行时可能发生,但编译器不要求我们必须处理。最常见的unchecked异常是 java.lang.NullPointerException ,当我们试图访问一个null对象的属性或方法时会出现此类异常。

Java异常处理机制

Java使用 try catch finally 语句结构来处理异常。

Bash
try {
  // 可能抛出异常的代码放在这里
  File file = new File("file.txt");
  FileReader reader = new FileReader(file);
} catch (FileNotFoundException e) {
  // 当在try块中抛出FileNotFoundException时,这里的代码会被执行
  System.out.println("文件未找到:" + e.getMessage());
} finally {
  // 不论是否发生异常,finally块中的代码总会被执行
  // 这里通常用于资源清理,如关闭文件流
  if (reader != null) {
    try {
      reader.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

在上述代码中,尝试打开一个文件,如果文件不存在,就会触发 FileNotFoundException ,并在catch块中处理该异常。最后,无论是否发生异常,finally块都会执行,用于关闭文件流以释放系统资源。

手动抛出异常(throw)

通过 throw 关键字,程序员可以主动抛出自定义的异常或系统内置异常。

Bash
if (value < 0) {
  throw new IllegalArgumentException("参数值不能为负数");
}

声明方法抛出异常(throws)

在方法签名中,使用 throws 关键字声明方法可能会抛出的异常,将异常处理的责任转移给方法的调用者。

public void readFile(String filePath) throws IOException {
  File file = new File(filePath);
  //...
}

try-with-resources语句

try-with-resources 是 Java 7 引入的一个特性,用于自动管理资源,特别是那些实现了 AutoCloseable Closeable 接口的资源,如文件流数据库连接等。使用 try-with-resources 语句可以确保在 try 代码块执行完毕后,资源能够正确、及时地关闭,即使发生异常也是如此。

示例,假设我们有一个实现了 AutoCloseable 接口的资源类:

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

public class TryWithResourcesExample {
  public static void main(String[] args) {
    // 假设我们有一个需要读取的文件
    String filePath = "example.txt";

    try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
      String line;
      while ((line = reader.readLine()) != null) {
        System.out.println(line);
      }
      // 在这里,reader 的 close() 方法会在 try 代码块结束时自动被调用
    } catch (IOException e) {
      e.printStackTrace();
    } // 无需在这里显式调用 reader.close()

    // 此时的 reader 已经被自动关闭,无需担心资源泄露问题
  }
}

在上面的例子中,BufferedReaderAutoCloseable 的一个子接口 Closeable 的实现。当 try 代码块执行完毕时,无论是否发生异常,BufferedReader 的 close() 方法都会被自动调用。这样,就无需在 finally 代码块中显式地关闭资源,从而简化了代码,并减少了忘记关闭资源导致资源泄露的风险。

try-with-resources 语句中的资源声明必须是局部变量并且这些资源在 try 代码块执行完毕后必须能够被关闭。如果资源不能被关闭(即 close() 方法抛出异常),那么这个异常会被抑制,并且原始的异常(如果有的话)会被重新抛出。如果需要处理 close() 方法抛出的异常,可以使用额外的 try-catch 块来捕获。

自定义异常

除了Java内置的异常类外,我们还可以创建自定义的异常类。这通常用于表示特定于应用程序的错误条件。要创建自定义异常类,需要继承自Exception类或其子类,并定义构造函数。

例如:

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

然后,可以在需要的地方抛出这个自定义异常:

throw new MyCustomException("自定义异常信息");

Java异常链

异常链是Java异常处理机制中的一个重要特性,允许在抛出新的异常时,将原始异常作为新异常的“原因”传递。这样做有助于保留原始异常的上下文信息,使得在后续处理中能够更准确地了解异常发生的根本原因。

在Java中,可以通过在构造新的异常时,将原始异常作为参数传递给新异常的构造函数,来创建异常链。这样,新异常就会包含原始异常的引用,从而形成一个链式结构。

简单的示例,演示如何使用Java异常链:

public class ExceptionChainExample {
  public static void main(String[] args) {
    try {
      method1();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

public static void method1() throws Exception {
  try {
    method2();
  } catch (Exception e) {
    throw new MyCustomException("在method1中捕获到异常", e); // 使用原始异常作为新异常的原因
  }
}

public static void method2() throws Exception {
  throw new IOException("method2中发生IO异常"); // 假设这里抛出了一个IOException
}

// 自定义异常类
 static class MyCustomException extends Exception {
    public MyCustomException(String message, Throwable cause) {
      super(message, cause);
    }
  }
}

在这个示例中,method2抛出了一个IOException。当method1捕获到这个异常时,创建了一个新的MyCustomException,并将原始的IOException作为原因传递给了新异常。这样,当在main方法中捕获到MyCustomException时,我们可以通过调用getCause()方法来获取原始的IOException,从而了解异常发生的根本原因。

异常链的好处

异常链的好处在于它保留了原始异常堆栈跟踪信息,使得在调试和排查问题时能够更容易地定位到问题的源头。同时,通过封装原始异常,还可以在自定义异常中添加更多的上下文信息,使得异常信息更加丰富和有用。

在处理异常时,建议总是尽量保留并使用异常链,以便在后续的处理中能够充分利用原始异常的信息。

异常处理的注意点

注意点

描述

避免空的catch块

空的catch块会捕获异常但不做任何处理,这会导致程序在出现问题时继续运行,可能会引发更严重的后果。因此,我们应该在catch块中至少记录异常信息或进行适当的处理。

细化异常处理

尽量捕获具体的异常类型,而不是简单地使用Exception来捕获所有异常。这样可以更准确地定位问题并进行处理。

使用finally块释放资源

finally块中释放资源是一个很好的习惯,无论是否发生异常,这些资源都会被正确释放。

合理设计异常结构

对于复杂的应用程序,合理设计异常结构可以帮助我们更好地管理异常。可以将相关的异常组织在一起,形成一个继承层次结构。

关键术语与概念总结

术语

描述

异常(Exception)

程序执行过程中遇到的问题或错误,如空指针异常(NullPointerException)文件未找到异常(FileNotFoundException)等。

Checked Exception

编译时异常,必须在编写代码时显式处理,如果不处理或声明抛出,编译器会报错。例如, IOException 。

Unchecked Exception

也称运行时异常,运行时可能出现的异常,一般由程序错误引起,如数组越界异常(ArrayIndexOutOfBoundsException)、空指针异常(NullPointerException)等。这类异常不必强制处理,但如果在运行时发生且未被捕获,程序会终止执行。

try catch finally

try 块放置可能抛出异常的代码。catch 块捕获并处理在 try 块中抛出的异常。finally 块无论是否发生异常,都会被执行的代码块,通常用于资源清理。

throw 关键字

手动抛出一个异常对象

throws 关键字

在方法签名中声明方法可能抛出的异常,将异常处理的责任转移给调用者。

异常链(Exception Chaining)

在一个异常中附加另一个异常,这样可以追踪异常发生的上下文。

自定义异常

通过创建一个新的类继承自 Exception 或其子类,可以定义自己的异常类型。

Java内置异常类

Java内置了许多异常类,这些类都是Throwable类的直接或间接子类。Throwable类有两个主要的子类:ErrorExceptionError类通常表示严重的问题,这些问题通常是Java虚拟机无法或不应该尝试修复的问题,如OutOfMemoryError或StackOverflowError。而Exception类及其子类则用于表示程序可以处理的异常情况。

Exception 类及其子类

一些常见的内置异常类及其描述:

输入输出异常

异常类

描述

IO

Exception

当应用程序发生输入输出异常时抛出。这是输入输出异常的根类。

FileNotFound

Exception

当试图打开指定路径名的文件失败时,抛出此异常。

EOF

Exception

当输入流已经关闭,或者已经到达流的末尾时,抛出此异常。

运行时异常

异常类

描述

Runtime

Exception

是那些可能在Java虚拟机正常运行期间抛出的异常的超类。编译器不会检查这类异常。

NullPointer

Exception

当应用程序试图在需要对象的地方使用null时,抛出该异常。

ArrayIndex

OutOfBounds

Exception

用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。

ClassCast

Exception

当试图将对象强制转换为不是实例的子类时,抛出该异常。

IllegalArgument

Exception

抛出的异常表明向方法传递了一个不合法或不适当的参数。

NumberFormat

Exception

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。

其他常见异常

异常类

描述

ClassNotFound

Exception

当应用程序试图加载类,而找不到定义类的.class 文件时,抛出该异常。

Interrupted

Exception

当线程在等待、睡眠或占用时,另一个线程中断它时,抛出该异常。

SQL

Exception

提供关于数据库访问错误或其他错误的详细信息。

Error 类及其子类

Error是程序无法处理的严重错误。例如,OutOfMemoryError 表明虚拟机没有更多的内存空间来分配对象,并且垃圾回收器也无法回收更多的空间。

异常类

描述

OutOf

MemoryError

当JVM无法为对象分配足够的内存空间时,会抛出这个错误。这通常发生在应用程序试图创建大量对象,而JVM的堆内存不足以容纳这些对象时。

Stack

OverflowError

当一个方法递归调用过深,或者一个线程请求的栈大小超过了JVM所允许的栈大小时,会抛出这个错误。栈溢出通常意味着程序有逻辑错误,例如无限递归。

NoClassDef

FoundError

当JVM尝试加载一个类,但没有找到定义该类的.class文件时,会抛出这个错误。这通常发生在类路径设置不正确,或者试图动态加载不存在的类时。

Virtual

MachineError

通用的错误类型,用于描述虚拟机运行时的严重问题。有两个常见的子类:StackOverflowError和OutOfMemoryError。

AWTError

与Java的抽象窗口工具包(AWT)相关的错误。AWT用于创建图形用户界面,如果在这个过程中出现严重问题,就可能抛出这个错误。

Assertion

Error

当断言(assert)失败时抛出。断言是编程时用于检查某个条件是否为真的语句,如果条件不为真,则抛出AssertionError。

Thread

Death

表示线程已请求死亡。虽然ThreadDeath是一个Error的子类,但它是唯一一个可以被捕获的Error。通常,应用程序不应该捕获这个错误,除非它们有特殊的处理逻辑。

由于Error类及其子类通常表示无法恢复严重问题,因此当这些错误发生时,应用程序通常无法继续正常运行。在编写Java程序时,虽然不需要显式地处理这些错误,但了解它们以及它们可能的原因仍

相关推荐

想减少Windows 11内存占用?请取消固定Teams

如果你想要提高Windows11系统的运行速度,那么可以禁用某些默认启用的功能和设置。如果你的Windows11是安装在已经停止支持的设备或者内存容量不高的旧设备,那么应该立即限制或禁用固...

Windows查看端口占用、查看PID对应的进程、并终止进程

Windows下:查看端口占用netstat-ano|findstr"端口号"获取到pid查看PID对应的进程tasklist|findstr"进程ID"...

计算机组成原理(36): 分时之一——进程

建立一个虚拟机VM目标:给每个程序一个自己的虚拟机“VirtualMachine”,程序并不知道其他的虚拟机。1.1进程(Process)为了捕获正在运行的程序,我们创建一个称为“进程(Proce...

window系统如何停止端口被占用的进程(高手版)

如上图1,作为开发人员是不是经常遇到这个问题?(Webserverfailedtostart.Port9527wasalreadyinuse.)当然,如果在你知道确实有某个进程正占...

电脑的文件无法删除咋回事?你需要这款神兵利器

很多朋友用电脑的时候,都遇到过文件无法删除的情况。这往往是由于文件被某个软件、进程所调用所引发的——在Windows中,某个文件如果被使用,这个文件可能就没法进行删除、重命名之类的操作了。想要进一步操...

Windows日志分析(windows 日志文件)

1.Windows日志文件简介1.1Windows日志核心分类1.系统日志系统日志包含由Windows系统组件记录的事件,记录系统进程和设备驱动程序的活动。由它审核的系统事件包括启动失败的设备驱动程...

电脑软件崩溃、闪退不用慌!DJS Tech 教你几招轻松解决

当你正全神贯注用电脑处理重要文件、沉浸在精彩的游戏世界,或是观看喜欢的视频时,软件突然崩溃、闪退,那一刻的烦躁简直难以言喻。别着急,DJSTech作为深耕计算机领域多年的专业团队,为你带来一系列超...

微软Win11推进淘汰控制面板,时间服务器配置迁移至设置应用

IT之家5月29日消息,科技媒体Winaero昨日(5月28日)发布博文,报道称微软在Windows11系统中,继续推进“淘汰控制面板”进程,配置时间服务器地址选项迁移到设置应...

微软 PowerToys更新,可帮你找出 Win11上哪些进程正在占用该文件

IT之家11月3日消息,微软针对Windows11和Windows10的PowerToys已经更新到了最新的0.64.0版本,并上线了一个名为“文件锁匠FileLock...

Windows基础操作 认识任务管理器(windows任务管理器的使用)

Windows基础操作:认识任务管理器任务管理器(TaskManager)是Windows系统中一个功能强大的实用工具,它为用户提供了实时监控系统资源、管理正在运行的程序和服务的能力。掌握任务管理器...

windows——netstat过滤(终止进程)

windows——netstat过滤(终止进程)在Windows操作系统中,使用netstat命令可以查看网络连接的状态。要过滤特定协议或端口的连接,可以使用以下命令:查看所有连接:netstat-...

只要这么做 Windows Defender与第三方就能和平共存啦

无论大家是否喜欢WindowsDefender,伴随着Windows10的不断升级,它已经成为系统的底层必备组件之一。虽然我们有各种各样的方法去关闭它,换用顺手的第三方,但只要更新打补丁,噩梦就来...

Win10如何彻底关闭wsappx进程(win10 wsappx怎么关闭)

win10如何彻底关闭wsappx进程?wsappx进程是什么?wsappx进程是Windows10系统的一部分,这个进程是WindowsStore和微软通用应用程序平台(UWP)的依赖进程。...

Windows环境黑客入侵应急与排查(黑客入侵电脑原理)

1文件分析1.1临时目录排查黑客往往可能将病毒放在临时目录(tmp/temp),或者将病毒相关文件释放到临时目录,因此需要检查临时目录是否存在异常文件。假设系统盘在C盘,则通常情况下的临时目录如下...

Windows 11 24H2 KB5044384出现大面积安装失败、任务管理器0进程等问题

Windows11KB5044384更新由于出现大量错误而无法在Windows1124H2上安装、其中包括一个奇怪的错误,即由于0x800f0922、0x800736b3和0x8...

取消回复欢迎 发表评论: