捕获或指定要求
有效的Java编程语言代码必须遵守捕获或指定需求,这意味着可能抛出某些异常的代码必须包含以下任一项:
捕获异常的try语句,try必须为异常提供处理程序,如捕获和处理异常中所述。
一种方法,指定它可以抛出异常,该方法必须提供一个throws子句,列出异常,如通过方法抛出指定异常中所述。
不符合捕获或指定要求的代码将无法编译。
并非所有异常都受捕获或指定要求的约束,为了理解原因,我们需要查看三个基本类别的异常,其中只有一个受要求限制。
三种异常第一种异常是已检查的异常,这些都是编写良好的应用程序应该预料到并从中恢复的异常情况。例如,假设应用程序提示用户输入文件名,然后通过将名称传递给java.io.FileReader的构造函数来打开该文件,通常,用户提供现有可读文件的名称,因此FileReader构造对象成功,并且应用程序的执行正常进行。但有时用户提供不存在的文件的名称,构造函数抛出java.io.FileNotFoundException,一个编写良好的程序将捕获此异常并通知用户该错误,可能提示更正的文件名。
已检查的异常情况受捕获或指定要求的约束,除Error、RuntimeException及其子类表示的异常外,所有异常都是经过检查的异常。
第二种异常是错误,这些是应用程序外部的异常情况,应用程序通常无法预测或恢复。例如,假设应用程序对于输入成功打开文件,但由于硬件或系统故障而无法读取文件,不成功的读取将抛出java.io.IOError,应用程序可能会选择捕获此异常,以便通知用户该问题 — 但是程序打印堆栈跟踪并退出也可能有意义。
错误不受捕获或指定要求的约束,错误是Error及其子类表示的异常。
第三种异常是运行时异常,这些是应用程序内部的异常情况,应用程序通常无法预测或恢复,这些通常表示编程bug,例如逻辑错误或API的不当使用。例如,考虑前面描述的应用程序将文件名传递给FileReader的构造函数,如果逻辑错误导致将null传递给构造函数,则构造函数将抛出NullPointerException,应用程序可以捕获此异常,但消除导致异常发生的bug可能更有意义。
运行时异常不受捕获或指定要求的约束,运行时异常是RuntimeException及其子类表示的异常。
错误和运行时异常统称为未经检查的异常。
通过方法抛出指定异常有时,代码可以捕获可能在其中发生的异常,但是,在其他情况下,最好让调用堆栈中进一步的方法处理异常。例如,如果你将ListOfNumbers类作为类包的一部分提供,则可能无法预测包的所有用户的需求,在这种情况下,最好不捕获异常并允许调用堆栈进一步的方法来处理它。
如果writeList方法没有捕获可能在其中发生的已检查异常,则writeList方法必须指定它可以抛出这些异常,让我们修改原始的writeList方法来指定它可以抛出而不是捕获它们的异常,这是不能编译的writeList方法的原始版本。
public void writeList() { PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt")); for (int i = 0; i < SIZE; i++) { out.println("Value at: " + i + " = " + list.get(i)); } out.close(); }
要指定writeList可以抛出两个异常,请将throws子句添加到writeList方法的方法声明中,throws子句包含throws关键字,后跟逗号分隔的该方法抛出的所有异常列表,该子句在方法名称和参数列表之后以及定义方法范围的大括号之前,这是一个例子。
public void writeList() throws IOException, IndexOutOfBoundsException {
请记住,IndexOutOfBoundsException是未经检查的异常,在throws子句中包含它不是强制性的,你可以仅写下面的内容。
public void writeList() throws IOException {绕过捕获或指定
一些程序员认为捕获或指定要求是异常机制中的一个严重缺陷,并通过使用未经检查的异常代替已检查的异常来绕过它,通常,不建议这样做,未经检查的异常 — 争议部分讨论何时适合使用未经检查的异常。
未经检查的异常 — 争议因为Java编程语言不需要捕获或指定未经检查的异常的方法(RuntimeException、Error及其子类),程序员可能会试图编写只抛出未经检查的异常的代码,或者让所有异常子类继承自RuntimeException,这两个快捷方式都允许程序员编写代码而不必担心编译器错误,也不必费心去指定或捕获任何异常。虽然这对程序员来说似乎很方便,但它会回避catch的意图或指定要求,并且可能会导致其他人使用你的类时出现问题。
为什么设计人员决定强制一个方法指定可以在其范围内抛出的所有未捕获的已检查异常?方法可以抛出的任何Exception都是该方法的公共编程接口的一部分,那些调用方法的人必须知道方法可以抛出的异常,以便他们可以决定如何处理它们,这些异常与该方法的编程接口一样,也是其参数和返回值的一部分。
下一个问题可能是:“如果记录方法的API非常好,包括它可以抛出的异常,为什么不指定运行时异常呢?”,运行时异常表示编程问题导致的问题,因此,无法合理地期望API客户端代码从它们恢复或以任何方式处理它们,这些问题包括算术异常,例如除以零;指针异常,例如尝试通过空引用访问对象;索引异常,例如尝试通过索引太大或太小来访问数组元素。
运行时异常可以在程序中的任何地方发生,而在典型的程序中,它们可以非常多,必须在每个方法声明中添加运行时异常会降低程序的清晰度,因此,编译器不要求你捕获或指定运行时异常(尽管你可以)。
抛出RuntimeException的常见做法之一是用户错误地调用方法,例如,方法可以检查其中一个参数是否错误地为null,如果参数为null,则该方法可能会抛出NullPointerException,这是一个未经检查的异常。
一般来说,不要因为你不希望指定方法可以抛出的异常而烦恼而抛出RuntimeException或创建RuntimeException的子类。
这是底线指南:如果可以合理地期望客户端从异常中恢复,则将其作为已检查的异常,如果客户端无法执行任何操作以从异常中恢复,请将其设置为未经检查的异常。
上一篇:什么是异常? 下一篇:捕获和处理异常文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/74024.html
Java™ 教程 Java教程是为JDK 8编写的,本页面中描述的示例和实践没有利用在后续版本中引入的改进。 Java教程是希望使用Java编程语言创建应用程序的程序员的实用指南,其中包括数百个完整的工作示例和数十个课程,相关课程组被组织成教程。 覆盖基础知识的路径 这些教程以书籍的形式提供,如Java教程,第六版,前往Amazon.com购买。 入门 介绍Java技术和安装Java开发软件并使用...
什么是异常? exception一词是exceptional event这一短语的简写。 定义:异常是在程序执行期间发生的事件,它会破坏程序指令的正常流程。 当方法中发生错误时,该方法会创建一个对象并将其交给运行时系统,该对象称为异常对象,包含有关错误的信息,包括错误发生时的类型和程序状态,创建异常对象并将其交给运行时系统称为抛出异常。 在方法抛出异常后,运行时系统会尝试查找处理它的内容,处理异常...
捕获和处理异常 本节描述如何使用三个异常处理程序组件 — try、catch和finally块 — 来编写异常处理程序,然后,解释了Java SE 7中引入的try-with-resources语句,try-with-resources语句特别适用于使用Closeable资源的情况,例如流。 本节的最后一部分将介绍一个示例,并分析各种场景中发生的情况。 以下示例定义并实现名为ListOfNumbe...
Thread对象 每个线程都与Thread类的实例相关联,使用Thread对象创建并发应用程序有两种基本策略。 要直接控制线程的创建和管理,只需在每次应用程序需要启动异步任务时实例化Thread。 要从应用程序的其余部分抽象线程管理,请将应用程序的任务传递给执行器。 本节介绍Thread对象的使用,Executors将与其他高级并发对象一起讨论。 定义和启动线程 创建Thread实例的应用程序...
如何抛出异常 在捕获异常之前,某些代码必须抛出一个,任何代码都可能抛出异常:你的代码,来自其他人编写的包中的代码,例如Java平台附带的包或Java运行时环境,无论抛出什么异常,它总是使用throw语句抛出。 你可能已经注意到,Java平台提供了许多异常类,所有类都是Throwable类的后代,并且所有类都允许程序区分在程序执行期间可能发生的各种类型的异常。 你还可以创建自己的异常类来表示你编写的...
阅读 1136·2021-11-10 11:35
阅读 2873·2021-09-24 10:35
阅读 2845·2021-09-22 15:38
阅读 2775·2019-08-30 15:43
阅读 1289·2019-08-29 18:39
阅读 2510·2019-08-29 15:22
阅读 2758·2019-08-28 18:17
阅读 578·2019-08-26 13:37