当前位置: 首页 > news >正文

面试题之Java的异常

Java的异常

  • Throwable 是所有 Java 程序中错误处理的父类 ,有两种直接子类: Error 和 Exception。

1. Error错误

  • Error 表示由 JVM 所侦测到的无法预期的错误,由于这是属于 JVM 层次的严重错误 ,导致 JVM 无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。
  • 常见的Error:
    • NotClassDefFountError(类未定义错误)
    • OutofMemoryError(内存溢出错误)
    • StackOverFlowError(栈溢出错误)

2. Exception异常

  • 程序本身可以捕获并且可以处理的异常。Exception 这种异常又分为两类:运行时异常和非运行时异常

2.1 编译时异常

  • 编译时异常又叫非运行时异常,或者受检异常。编译器会检查此类异常,也就是说当编译器检查到应用中的某处可能会有此类异常时,将会提示你处理本异常,要么使用 try-catch 捕获,要么使用方法签名中用 throws 关键字抛出,否则编译不通过。
  • 常见的编译时异常:
    • IOException:输入输出流异常
    • SQLException:数据库操作异常
    • ClassNotFoundException:类找不到的异常
    • TimeoutException:执行超时异常

2.2 运行时异常

  • 运行时异常也叫非受检异常,是指编译通过但在程序运行时出现的异常。当出现这样的异常时,总是由虚拟机接管。

  • 出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由 Thread.run()抛出 ,如果是单线程就被 main() 抛出 。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。

  • 运行时异常是 Exception 的子类,也有一般异常的特点,是可以被 Catch 块处理的,不过一般情况下我们不对其进行处理。也就是说,如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。、

  • 常见的运行时异常:

    • NullPointerException: 空指针引用异常
      • 调用 null 对象的实例方法。
      • 访问或修改 null 对象的字段。
      • 将 null 作为一个数组,获得其长度。
    • ClassCastException:类型强制转换异常
      • 试图将对象强制转换为不是实例的子类
    • ArithmeticException:算术运算异常
    • ArrayIndexOutOfBoundsException:下标越界异常
    • IllegalArgumentException:传递非法参数异常。
    • ConcurrentModificationException:并发修改异常

在提到ConcurrentModificationException时可以多聊一些,这个异常会比前面的一些异常显得高级一点,让面试官知道你学习过JUC中的安全集合,确实是自己实践验证过。如果对有兴趣了解更多关于并发修改异常的知识,可以看我的这篇文章:JUC集合线程安全

3. 关于异常的面试题

3.1 Error 和 Exception 区别是什么?

  • Error 类型的错误通常为虚拟机相关错误,如内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA 应用程序也不应对这类错误进行捕获,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复。
  • Exception 类的错误是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。

3.2 运行时异常和编译时异常(受检异常)区别是什么?

  • 运行时异常包括 RuntimeException 类及其子类,表示程序在运行期间可能出现的异常。 Java 编译器不会检查运行时异常。
  • 受检异常是 Exception 中除 RuntimeException 及其子类之外的异常。 Java 编译器会检查受检异常。
  • 区别:是否强制要求调用者必须处理此异常,如果强制要求调用者必须进行处理,那么就使用受检异常,否则就选择非受检异常(RuntimeException)。一般来讲,如果没有特殊的要求,我们建议使用RuntimeException异常。

3.3 JVM 是如何处理异常的?

  • 在一个方法中如果发生异常,这个方法会创建一个异常对象,并转交给 JVM,该异常对象包含异常名称、异常描述以及异常发生时应用程序的状态。创建异常对象并转交给 JVM 的过程称为抛出异常。可能有一系列的方法调用,最终才进入抛出异常的方法,这一系列方法调用的有序列表叫做调用栈
  • JVM 会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。当 JVM发现可以处理异常的代时,会把发生的异常传递给它。如果 JVM 没有找到可以处理该异常的代码块,JVM 就会将该异常转交给默认的异常处理器(默认处理器为 JVM 的一部分),默认异常处理器打印出异常信息并终止应用程序。

3.4 throw 和 throws 的区别是什么?

  • Java 中的异常处理除了包括捕获异常和处理异常(try-catch)之外,还包括声明异常和拋出异常(throws),可以通过 throws 关键字在方法上声明该方法要拋出的异常,或者在方法内部通过 throw 拋出异常对象。
  • throws 关键字和 throw 关键字在使用上的几点区别如下:
    • throw 关键字用在方法内部,只能用于抛出一种异常,用来抛出方法或代码块中的异常,受查异常和非受查异常都可以被抛出。
    • throws 关键字用在方法声明上,可以抛出多个异常,用来标识该方法可能抛出的异常列表。一个方法用 throws 标识了可能抛出的异常列表,调用该方法的方法中必须包含可处理异常的代码,否则也要在方法签名中用 throws 关键字声明相应的异常。

3.5 final、finally、finalize 有什么区别?

  • final 是一个关键字,可以修饰类、变量、方法。修饰类表示该类不能被继承,修饰方法表示该方法不能被重写,修饰变量表示该变量是一个常量不能被重新赋值。
  • finally 一般作用在 try-catch 代码块中,在处理异常的时候,通常我们将一定要执行的代码方法 finally 代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码
  • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,Java 中允许使 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

3.6 ClassNotFoundException 和 NoClassDefFoundError区别?

  • ClassNotFoundException 是一个编译时异常,表示类未找到,需要显式地使用 try-catch 对其进行捕获和处理,或在方法签名中用 throws 关键字进行声明。当使用 Class.forName、ClassLoader.loadClass、ClassLoader.findSystemClass 动态加载类到内存的时候,通过传入的类路径参数没有找到该类,就会抛出该异常。
  • NoClassDefFoundError 是一个 Error 类型的错误,表示类未定义,是由 JVM 引起的,不应该尝试捕获这个异常。引起该异常的原因是 JVM 或 ClassLoader 尝试加载某类时在内存中找不到该类的定义。
  • 总结:
    • ClassNotFoundException 是编译时异常,表示类未找到;NoClassDefFoundError 是 Error 类型的错误,表示类未定义。
    • ClassNotFoundException 需要用 try-catch 进行捕获或者使用 throws 抛出;NoClassDefFoundError 由 JVM 引起,不由我们去捕获或抛出。
    • 产生异常的原因不一样

3.7 try-catch-finally 中哪个部分可以省略?

  • 以下三种情况都是编译可以通过的:
    try-catch
    try-finally
    try-catch-finally
  • 可以省略 catch 或者 finally。catch 和 finally 不可以同时省略

3.8 如果 catch 中 return 了,finally 还会执行吗?

  • 答案是会执行

    • finally 的作用就是,无论出现什么状况,finally 里的代码一定会被执行。
    • 如果在 catch 中 return了,也会在 return之前,先执行 finally 代码块。
    • 而且如果 finally 代码块中含有 return 语句,会覆盖其他地方的 return。
    • 对于基本数据类型的数据,在 finally 块中改变 return 的值对返回值没有影响,而对引用数据类型的数据会有影响。
  • 基本数据类型的数据:

    public class Test {
        public static void main(String[] args) {
            System.out.println(MyTest());//输出结果为20,说明在 finally 块中改变 return 的值对返回值没有影响
        }
    
        public static int MyTest() {
            int a;
            try {
                a = 10;
                a = 10 / 0;//制造异常
            } catch (Exception e) {
                e.printStackTrace();
                a = 20;
                return a;
            } finally {
                a = 30;
            }
            return a;
        }
    }
    
  • 引用类型的数据:

    public class Test08 {
        public static void main(String[] args) {
            System.out.println(MyTest().getName());//输出结果为狗C,说明在 finally 块中改变 return 的值对引用数据类型的										数据会有影响
        }
    
        public static Dog MyTest(){
            Dog dog = new Dog();
            try {
                dog.setName("狗A");
                int a = 10 / 0;//制造异常
            } catch (Exception e) {
                e.printStackTrace();
                dog.setName("狗B");
                return dog;
            } finally {
                dog.setName("狗C");
            }
            return dog;
        }
    }
    
    class Dog{
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

相关文章:

  • k8s helm Seata1.5.1
  • 物业公司如何解决降本增收?快鲸智慧社区系统来帮你
  • MobTech 短信验证Android端 API
  • kafka学习总结
  • 政策汇总 | 川渝发布若干政策支持双城经济圈健康发展、岷山行动计划第三批项目申报解答......近期16个政策汇总
  • Vue3.0中使用路由进行跳转和传参以及取值
  • 迷茫了3年:做完这个测试项目,我终于决定辞职
  • 时间相关模块
  • LINU下登录脚本的执行顺序
  • MySQL 文本函数和窗口函数
  • springboot+cloud实战派PDF让开发和微服务架构像喝水一样简单
  • QML自定义的日历控件
  • Hive的 mapreduce 计算例子
  • 代码演示傅里叶合成演示
  • 【实用工具】magic-api接口快速开发框架
  • JavaScript DOM 10 - 滚动
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • JavaScript服务器推送技术之 WebSocket
  • Just for fun——迅速写完快速排序
  • mysql 数据库四种事务隔离级别
  • vue-router 实现分析
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 构建工具 - 收藏集 - 掘金
  • 如何实现 font-size 的响应式
  • 软件开发学习的5大技巧,你知道吗?
  • 用mpvue开发微信小程序
  • 第二十章:异步和文件I/O.(二十三)
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • (10)ATF MMU转换表
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • *p++,*(p++),*++p,(*p)++区别?
  • .net 8 发布了,试下微软最近强推的MAUI
  • .Net6 Api Swagger配置
  • ??在JSP中,java和JavaScript如何交互?
  • @KafkaListener注解详解(一)| 常用参数详解
  • [16/N]论得趣
  • [Android]如何调试Native memory crash issue
  • [AutoSar NVM] 存储架构
  • [bzoj2957]楼房重建
  • [CSS]文字旁边的竖线以及布局知识
  • [Excel] vlookup函数
  • [Excel]如何找到非固定空白格數列的條件數據? 以月份報價表單為例
  • [HAOI2016]食物链
  • [javaSE] 看知乎学习工厂模式
  • [js]- 两个对象的合并(Object.assign)
  • [LeetCode][138]【学习日记】深拷贝带有随机指针的链表
  • [NLP] 使用Llama.cpp和LangChain在CPU上使用大模型
  • [Sdoi2010]地精部落
  • [SSD综述 1.4] SSD固态硬盘的架构和功能导论
  • [ThinkPHP]源码阅读:Model的获取器
  • [Web开发] IE8的User-Agent 字符串
  • [笔记] iperf3.1.3源码下载与交叉编译