面试突击:深入理解 Java 中的异常

2024-06-23 01:12

本文主要是介绍面试突击:深入理解 Java 中的异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文已收录于:https://github.com/danmuking/all-in-one(持续更新)

前言

哈喽,大家好,我是 DanMu。今天想和大家聊聊 Java 中的异常。异常处理是一种重要的概念,因为程序总是会出现各种意料之外的问题:有可能是逻辑错误,也可能某位小可爱想看一个练习了 null 年半的练习生跳舞,程序不可能永远正确运行。但是,我们也希望程序在出错之后可以继续运行,不能影响正常用户的使用。因此,我们需要一种机制,保证程序能够在出错后进行一定程度的处理后继续运行。

Java 异常概览:

先来看看 Java 中的异常体系异常.drawio.png

Throwable

在 Java 中,所有的异常相关类都继承于一个父类,java.lang 包中的 Throwable 类。

public class Throwable implements Serializable

Throwable 中比较重要的方法有:

  • String getMessage(): 返回异常发生时的简要描述
  • String toString(): 返回异常发生时的详细信息
  • String getLocalizedMessage(): 返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同
  • void printStackTrace(): 在控制台上打印 Throwable 对象封装的异常信息

Exception 和 Error

Throwable 有两个重要的子类,Exception 和 Error:
从字面含义来说,Exception 翻译为异常,Error 翻译为错误,显然 Error 代表这更加严重的问题,在使用中也同样如此。
Error:
Error 属于程序无法处理的错误 ,不建议通过 catch 捕获 。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。
Exception:
程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异常,可以不处理)。

由于 Error 通常不建议进行处理,所以在代码编写中,我们更多接触的通常是 Exception。

Checked Exception(受检异常)和 Unchecked Exception(非受检异常)?

Checked Exception
Checked Exception受检查异常 ,Java 代码在编译过程中,如果受检查异常没有被 catch 或者 throws 关键字处理的话,就没办法通过编译。
比如这个简单的例子:
image.png
除了 RuntimeException 及其子类以外,其他的 Exception 类及其子类都属于受检查异常 。常见的受检查异常有:IO 相关的异常、ClassNotFoundException、SQLException…。
Unchecked Exception
Unchecked Exception不受检查异常 ,Java 代码在编译过程中 ,我们**即使不处理不受检查异常也可以正常通过编译。**这类异常通常与到程序运行时的状态有关。Unchecked Exception 主要包括 RuntimeException 及其子类,常见的有

  • NullPointerException(空指针错误)
  • IllegalArgumentException(参数错误比如方法入参类型错误)
  • NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException的子类)
  • ArrayIndexOutOfBoundsException(数组越界错误)
  • ClassCastException(类型转换错误)
  • ArithmeticException(算术错误)
  • ……

建议大家根据需要记上 3-4 个,面试的时候如果问到能适当的举出几个例子。

image.png

try-catch-finally 和 try-with-resources

try-catch-finally

try-catch-finally 由 3 部分组成

  • try:用于捕获异常其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
  • catch:用于处理 try 捕获到的异常。
  • finally:**无论是否捕获或处理异常,finally 块里的语句都会被执行。**当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。

这是一个简单的例子:

public static void main(String[] args) {try {int[] myNumbers = {1, 2, 3};System.out.println(myNumbers[10]);} catch (Exception e) {System.out.println("Something went wrong.");} finally {System.out.println("The 'try catch' is finished.");}}

注意:不要在 finally 语句块中使用 return! 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。这是因为 try 语句中的 return 返回值会先被暂存在一个本地变量中,当执行到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。

finally 中的代码一定会执行吗?

不一定!在某些情况下,finally 中的代码不会被执行。
就比如说 finally 之前虚拟机被终止运行的话,finally 中的代码就不会被执行。

try {System.out.println("Try to do something");throw new RuntimeException("RuntimeException");
} catch (Exception e) {System.out.println("Catch Exception -> " + e.getMessage());// 终止当前正在运行的Java虚拟机System.exit(1);
} finally {System.out.println("Finally");
}

输出:

Try to do something
Catch Exception -> RuntimeException

另外,在以下 2 种特殊情况下,finally 块的代码也不会被执行:

  1. 程序所在的线程死亡。
  2. 强制关闭 CPU。

虽然在实际应用中很难遇到这样子的场景,但是在面试时不少面试官还是很喜欢问这类问题,所以还是要稍微注意一下

try-with-resources

在 Java 中,所有被打开的系统资源,比如流、文件或者Socket连接等,都需要被开发者手动关闭,否则随着程序的不断运行,资源泄露将会累积成重大的生产事故。但是每一个打开的资源都伴随着一个需要被处理的异常,如果一次性需要打开多个资源,那异常的处理就会变成一场噩梦,比如这个例子:

public class Demo {public static void main(String[] args) {BufferedInputStream bin = null;BufferedOutputStream bout = null;try {bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")));int b;while ((b = bin.read()) != -1) {bout.write(b);}}catch (IOException e) {e.printStackTrace();}finally {if (bin != null) {try {bin.close();}catch (IOException e) {e.printStackTrace();}finally {if (bout != null) {try {bout.close();}catch (IOException e) {e.printStackTrace();}}}}}}
}

Fxxk!我只是想要读写两个文件,异常处理的代码竟然比业务代码长的多!这是因为,我们不仅需要关闭 BufferedInputStream ,还需要保证如果关闭 BufferedInputStream 时出现了异常, BufferedOutputStream 也要能被正确地关闭。所以我们不得不借助 finally 中嵌套 finally 大法。可以想到,打开的资源越多,finally 中嵌套的将会越深!
为了释放程序员的双手,在 1.7 中 Java 新增了一个 try-with-resources 语法糖,我们重新改写一下上面的例子

public class TryWithResource {public static void main(String[] args) {try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {int b;while ((b = bin.read()) != -1) {bout.write(b);}}catch (IOException e) {e.printStackTrace();}}
}

只需要将要打开的资源放在try后的()中,不同资源间用;分割,就可以自动完成资源的关闭。代码一下子就清爽了!try-with-resources 虽好但是也有几点需要注意

  1. 适用范围(资源的定义): 任何实现 java.lang.AutoCloseable或者 java.io.Closeable 的对象
  2. 关闭资源和 finally 块的执行顺序: 在 try-with-resources 语句中,任何 catch 或 finally 块在声明的资源关闭后运行

点关注,不迷路

好了,以上就是这篇文章的全部内容了,如果你能看到这里,非常感谢你的支持!
如果你觉得这篇文章写的还不错, 求点赞👍 求关注❤️ 求分享👥 对暖男我来说真的 非常有用!!!
白嫖不好,创作不易,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !

最后推荐我的IM项目DiTing(https://github.com/danmuking/DiTing-Go),致力于成为一个初学者友好、易于上手的 IM 解决方案,希望能给你的学习、面试带来一点帮助,如果人才你喜欢,给个Star⭐叭!

参考资料

Java基础常见面试题总结(下)

这篇关于面试突击:深入理解 Java 中的异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085912

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory