让我们探讨以下问题,这些问题很可能出现在 Java 开发人员有关异常的技术面试中。
Java中什么是异常?
Java 中的异常处理是如何工作的?
Java中的异常处理关键字是什么?
throw 和 throws 关键字的目的是什么?
你如何处理异常?
解释 Java 异常层次结构。
如何捕获多个异常?
Java 中检查异常和非检查异常有什么区别?
Java 中的 throw 和 throws 关键字有什么区别?
异常和错误有什么区别?
Java 中的是什么 OutOfMemoryError ?
Java 中的链式异常是什么?
如何用 Java 编写自定义异常?
Java中的final、finally和finalize有什么区别?
当main方法抛出异常时会发生什么?
什么是 try-with-resources 语句?
什么是堆栈跟踪以及它与异常有何关系?
Java异常有什么优点?
您可以在 lambda 表达式体内抛出任何异常吗?
当重写抛出异常的方法时,我们需要遵循哪些规则?
异常处理的最佳实践有哪些?
1. Java中的异常是什么?
异常是在程序执行期间发生并扰乱程序指令的正常流程的事件。
在Java 异常处理指南中阅读有关 Java 异常的更多信息 !
2. Java 中的异常处理是如何工作的?
以下步骤演示了 Java 中异常处理的工作原理:
步骤1:当方法内发生错误时,该方法创建一个对象并将其交给运行时系统,该对象称为异常对象。异常对象包含有关错误的信息,包括错误的类型和错误发生时程序的状态。创建异常对象并将其交给运行时系统称为抛出异常。
第 2 步: 方法抛出异常后,运行时系统会尝试找到处理异常的方法。处理异常的可能的“东西”的集合是已被调用以到达发生错误的方法的方法的有序列表。方法列表称为 调用堆栈。下图显示了三个方法调用的调用堆栈,其中调用的第一个方法具有异常处理程序。
步骤3: 运行时系统在调用堆栈中搜索包含可以处理异常的代码块的方法。该代码块称为 异常处理程序。搜索从发生错误的方法开始,然后按照与调用方法相反的顺序遍历调用堆栈。当找到合适的处理程序时,运行时系统会将异常传递给该处理程序。
如果抛出的异常对象的类型与处理程序可以处理的类型匹配,则认为该异常处理程序是合适的。
步骤 4: 所选择的异常处理程序据说可以捕获异常。如果运行时系统彻底搜索调用堆栈上的所有方法而没有找到适当的异常处理程序,如下图所示,则运行时系统(以及程序)将终止。
阅读更多内容,请 参阅 Java 中异常处理如何工作的示例。
3. Java中的异常处理关键字是什么?
Java 异常处理通过五个关键字进行管理:
1. try:将可能引发异常的代码包含在 try 块中。如果块内发生异常 try ,则该异常由与其关联的异常处理程序处理。该 try 块包含至少一个 catch 块或 finally 块。
2. catch: Java catch 块用于处理异常。它必须仅在块之后使用 try 。您可以将多个 catch 块与单个try.
3 throw.:有时,我们明确想要创建一个异常对象,然后抛出它以停止程序的正常处理。该 throw 关键字用于向运行时抛出异常来处理它。
4 throws.:当我们在方法中抛出任何已检查异常并且不处理它时,我们需要 throws 在方法签名中使用关键字来让调用程序知道该异常可能是由该方法抛出的。该 方法可能会处理这些异常或使用 关键字caller 将其传播到其 方法。我们可以在 throws 子句中提供多个异常,它也可以与该方法一起使用 。caller throws main()
5. finally:该 finally 块是可选的,只能与该块一起使用try-catch 。由于异常会停止执行过程,因此我们可能会打开一些资源而不会被关闭,因此我们可以使用finally块。finally 无论是否发生异常,该 块都会被执行。
该图总结了这些关键字的用法。
有关所有五个关键字的更多信息,请参阅Java 中的异常处理关键字及其示例。
4. Throw 和 Throws 关键字的目的是什么?
该throws 关键字用于指定方法在执行期间可能引发异常。它在调用方法时强制执行显式异常处理:
该throw 关键字允许我们抛出异常对象来中断程序的正常流程。当程序无法满足给定条件时最常用:
在这里阅读有关 throws 和 throw 关键字的更多信息: Java throw Keyword with Example; Java 用 Example 抛出关键字。
5. 如何处理异常?
您可以使用以下语句来处理异常 try-catch-finally:
可能发生异常的代码块包含在 try 块中。该块也称为“受保护”或“受保护”代码。如果发生异常, catch 则执行与抛出的异常匹配的块。如果不是, catch 则忽略所有块。该 finally 块总是在 try 块退出后执行,无论块内是否抛出异常。
在这里阅读有关如何处理异常的更多信息: Java 异常处理教程。
6. 解释 Java 异常层次结构。
从Throwable类继承的对象,包括直接后代(直接从Throwable类继承的对象)和间接后代(从Throwable类的子代或孙代继承的对象)。
Throwable有两个直接后代:
Error 班级
Exception 班级
下图说明了Throwable类及其最重要的子类的类层次结构。
Error 类:当Java虚拟机中发生动态链接失败或其他硬故障时,虚拟机会抛出 Error.
示例: VirtualMachineError、 OutOfMemoryError、 UnKnownError、 StackOverflowError等。
Exception 类:大多数程序抛出并捕获从类派生的对象 exception 。异常表明出现了问题,但不是严重的系统问题。例如,在处理 时 FileNotFoundException,我们应该捕获此异常并向用户提供有用的消息并正确记录它以用于调试目的。异常是 parent 所有检查异常的类。
RuntimeException 类:这提供了一个异常子类, RuntimeException该子类是为指示 API 使用不正确的异常而保留的。运行时异常的一个示例是 NullPointerException,当方法尝试通过空引用访问对象的成员时,就会发生这种异常。
在这里阅读有关 Java 异常层次结构的更多信息: Java 中的异常层次结构。
7. 如何捕获多个异常?
有三种方法可以处理代码块中的多个异常。
您应该记住,建议的做法是使用尽可能准确的异常处理程序。
过于宽泛的异常处理程序可能会使您的代码更容易出错、出现 catch 未预料到的异常,并导致程序出现意外行为。
第二种方法是实现多个 catch 块:
请注意,如果异常具有继承关系,则子类型必须在前,父类型在后。如果我们不这样做,就会导致编译错误。
第三种是使用多重 catch 块:
该功能首次在 Java 7 中引入,可减少代码重复并使其更易于维护。
阅读更多内容,请参阅 Java try/catch 块及其示例。
8. Java 中的检查异常和非检查异常有什么区别?
1. 检查异常应该在代码中使用 try-catch 块进行处理,否则,方法应该使用 throws 关键字让调用者知道该方法可能抛出的检查异常。未经检查的异常不需要在程序中处理或在throws 方法的子句中提及它们。
2.异常是所有已检查异常的超类,而 RuntimeException 是所有未检查异常的超类。请注意,这 RuntimeException 是子类Exception.
3. 检查异常是需要在代码中处理的错误场景,否则,您将得到编译时错误。例如,如果你用来 FileReader 读取一个文件,它会抛出 , FileNotFoundException 我们必须在try-catch 块中捕获它,或者再次将其抛出到 caller 方法中。未经检查的异常主要是由糟糕的编程引起的,例如, NullPointerException 在未确保对象引用不为空的情况下调用对象引用的方法时。我可以编写一个方法来删除字符串中的所有元音。调用者有责任确保不传递空字符串。我可能会更改方法来处理这些场景,但理想情况下,调用者应该处理这个问题。
4. 检查异常和非检查异常也分别称为编译时异常和运行时异常。
9. Java中的Throw和Throws关键字有什么区别?
该 throws 关键字与方法签名一起使用来声明该方法可能抛出的异常,而该 throw 关键字用于中断程序流程并将异常对象移交给运行时来处理它。
阅读更多内容,请参阅Java 中的 Throw 和 Throws 之间的区别。
10. 异常和错误有什么区别?
An exception 是表示可以恢复的条件的事件,而 an error 表示通常无法恢复的外部情况。
JVM 抛出的所有错误都是其子类的实例 Error 或其子类之一。比较常见的包括:
OutOfMemoryError – 当 JVM 由于内存不足且垃圾收集器无法提供更多可用对象而无法分配更多对象时抛出。
StackOverflowError – 当线程的堆栈空间耗尽时发生。这通常是因为应用程序递归得太深。
ExceptionInInitializerError – 表示在评估静态初始值设定项期间发生意外异常。
NoClassDefFoundError – 当类加载器尝试加载类的定义但找不到它时抛出,通常是因为在类路径中找不到所需的类文件。
UnsupportedClassVersionError – 当 JVM 尝试读取类文件并确定文件中的版本不受支持时发生,通常是因为该文件是使用较新版本的 Java 生成的
尽管可以使用语句来处理错误 try ,但这不是推荐的做法,因为不能保证程序在抛出错误后能够可靠地执行任何操作。
在这里阅读有关此主题的更多信息: Java 中的异常层次结构。
11. Java中的OutOfMemoryError是什么?
Java OutOfMemoryError 中的 是 java.lang 的子类。 VirtualMachineError 当 JVM 堆内存耗尽时,它会抛出。
下图说明了 Error 类的类层次结构。
我们可以通过 Java 选项提供更多内存来运行 Java 应用程序来修复此错误。
12. Java 中的链式异常是什么?
链接异常功能允许您将另一个异常与一个异常关联起来。第二个异常描述了第一个异常的原因。
例如,想象一种情况,一个方法 ArithmeticException 由于尝试除以零而抛出一个异常。但问题的实际原因是发生了I/O错误,导致除数设置不当。尽管该方法肯定会抛出一个 ArithmeticException异常,因为这是发生的错误,但您可能还想让调用代码知道根本原因是 I/O 错误。链接异常使您可以处理这种情况以及存在异常层的任何其他情况。这个概念是在 JDK 1.4 中引入的。
在此处阅读有关链式异常功能的更多信息: Java Chained Exceptions with Example。
13. 如何用Java编写自定义异常?
在较大的应用程序中,大多数情况下我们需要自定义异常来表示业务异常,其级别高于 JDK 定义的技术异常。
以下是创建自定义异常的步骤:
创建一个新类,其名称应以 结尾 Exception, 例如 ClassNameException. 这是区分异常类和常规类的约定。
使该类 extends 成为该类的子类型的例外之一 java.lang.Exception 。通常,自定义异常类总是直接从该类扩展 Exception 。
创建一个带有 String 参数的构造函数,参数是异常的详细消息。在这个构造函数中,只需调用超级构造函数并传递消息即可。在 Java 中,有两种类型的异常 - 检查异常和非检查异常。