Java异常探秘:从错误中学习

简介: Java异常探秘:从错误中学习

常用 API

异常的分类

异常对象都是派生于 Throwable 类的一个实例。如果 Java 中内置的异常类不能够满足需求,用户可以创建自己的异常类。

对于那些可能被他人使用的 Java 方法,应该根据异常规范,在方法的首部末尾来声明这个方法可能抛出的异常,如果可能有多个异常,那么异常名通过逗号分隔。

一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控制( Error ),要么就应该避免发生( RuntimeException )。如果方法没有声明所有可能发生的受查异常,编译器就会发出一个错误消息。

除了声明异常之外,还可以捕获异常。这样会使异常不被抛到方法之外,也不需要 throws 规范。

Error

Error 类层次结构描述了 Java 运行时系统的内部错误和资源耗尽错误。 应用程序不应该抛出这种类型的对象。 如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力了。这种情况很少出现。

Exception

Exception 又分解为两个分支: 一个分支派生 RuntimeException;另一个分支包含其他异常。划分两个分支的规则是:由程序错误导致的异常属于 RuntimeException ; 而程序本身没有问题,但由于像 I/O错误这类问题导致的异常属于其他异常。

RuntimeException 和 Error 是不会受到编译器检查的,叫作非检查异常。如果出现 RuntimeException 异常, 那么就一定是你的问题,属于Bug。

其他的异常类型是受检查异常,编译器将核查是否为所有的受査异常提供了异常处理器。

手动抛出异常

一旦方法抛出了异常,这个方法就不可能返回到调用者。也就是说,不必为返回的默认值或错误代码担忧。

手动抛出异常使用:throw new EOFException( );

自定义异常

定义一个派生于Exception 的类, 或者派生于 Exception 子类的类。

捕获异常

捕获到异常后,打印详细信息可以使用:exception.printStackTrace( );

异常对象可能包含与异常本身有关的信息。可以使用 e.getMessage( ) 获得对象的更多信息,使用e.getClass().getName( ) 得到异常对象的实际类型。

try catch 语句

如果在 try 语句块中的任何代码抛出了一个在 catch 子句中说明的异常类,那么程序将跳过 try 语句块的其余代码,并且开始执行 catch 子句中的处理器代码。

如果在 try 语句块中的代码没有拋出任何异常,那么程序将跳过 catch 子句。

如果方法中的任何代码拋出了一个在 catch 子句中没有声明的异常类型,那么这个方法就会立刻退出。

捕获多个异常

捕获后再次抛出

在 catch 子句中可以抛出一个异常,这样做的目的是改变异常的类型。捕获到异常后进行包装或者修改后重新抛出。方便后续逻辑处理,注意一定要使用initCause方法将原始的异常信息保留下来方便日志定位。

强烈建议使用这种包装技术。这样可以让用户抛出子系统中的高级异常,而不会丢失原始异常的细节。

finally子句

不管是否有异常被捕获,finally 子句中的代码都被执行。通常用来关闭资源。try 语句可以只有 finally 子句, 而没有 catch 子句。 强烈建议解耦合 try/catch和 try/finally语句块。

内层的 try 语句块只有一个职责,就是确保关闭输入流。外层的 try 语句块也只有一个职责,就是确保报告出现的错误。这种设计方式不仅清楚,而且还具有一个功能,就是将会报告 finally 子句中出现的错误。

另外如果 finally 子句中也有一个 return 语句,这个返回值将会覆盖原始的返回值。

带资源的 try 语句

这个块正常退出时,或者存在一个异常时,都会调用 in.close( ) 方法,就好像使用了 finally 块一样。而且 try( ) 的内容可以指定多个资源,用;分隔。

分析堆栈轨迹

可以调用 Throwable 类的 printStackTrace 方法访问堆栈轨迹的文本描述信息。

一种更灵活的方法是使用 getStackTrace 方法, 它会得到 StackTraceElement 对象的一个数组, 可以在你的程序中分析这个对象数组。StackTraceElement 类含有能够获得文件名和当前执行的代码行号的方法,同时,还含有能够获得类名和方法名的方法。 toString 方法将产生一个格式化的字符串, 其中包含所获得的信息。

异常使用技巧

  1. 只在异常情况下使用异常机制
  2. 捕获时不要过分地细化异常
  3. 利用异常层次结构,找到合适的异常
  4. 在检测错误时,苛刻要比放任更好
  5. 早抛出,晚捕获

断言

断言机制允许在测试期间向代码中插入一些检査语句。当代码发布时,这些插人的检测语句将会被自动地移走。

可以使用下面两种格式:

  • assert 表达式;
  • assert 表达式: 信息;

这两种形式都会对条件进行检测,如果结果为 false,则抛出一个 AssertionError 异常。在第二种形式中,表达式将被传人 AssertionError 的构造器,并转换成一个消息字符串。

在默认情况下,断言被禁用。可以在运行程序时用 -enableassertions-ea选项启用。

断言只应该用于在测试阶段确定程序内部的错误位置。断言是一种测试和调试阶段所使用的战术性工具,而日志记录是一种在程序的整个生命周期都可以使用的策略性工具。

笔记大部分摘录自《Java核心技术卷I》,含有少数本人修改补充痕迹。

相关文章
|
4天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
4天前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
|
26天前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
86 43
Java学习十六—掌握注解:让编程更简单
|
5天前
|
IDE 前端开发 Java
怎样避免 Java 中的 NoSuchFieldError 异常
在Java中避免NoSuchFieldError异常的关键在于确保类路径下没有不同版本的类文件冲突,避免反射时使用不存在的字段,以及确保所有依赖库版本兼容。编译和运行时使用的类版本应保持一致。
|
7天前
|
Java 编译器
如何避免在 Java 中出现 NoSuchElementException 异常
在Java中,`NoSuchElementException`通常发生在使用迭代器、枚举或流等遍历集合时,尝试访问不存在的元素。为了避免该异常,可以在访问前检查是否有下一个元素(如使用`hasNext()`方法),或者使用`Optional`类处理可能为空的情况。正确管理集合边界和条件判断是关键。
|
10天前
|
Java
Java异常捕捉处理和错误处理
Java异常捕捉处理和错误处理
11 1
|
11天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
12天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
27 2
|
1月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
31 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
18天前
|
Java
如何在 Java 中处理“Broken Pipe”异常
在Java中处理“Broken Pipe”异常,通常发生在网络通信中,如Socket编程时。该异常表示写入操作的另一端已关闭连接。解决方法包括:检查网络连接、设置超时、使用try-catch捕获异常并进行重试或关闭资源。