关于JAVA中的异常类及异常处理机制与基本原则

简介: 在编码过程中经常需要处理程序中的异常,然而对于异常处理也有相应的处理原则及内部处理机制,合理的异常处理机制也有利于提升程序的执行性能。

异常定义
异常是指程序在执行过程中出现了意外情况,导致程序被迫中断运行。
1、Throwable、Exception、Error 区别
Throwable类是所有异常和错误的超类,其中Exception 和 Error都继承自Throwable类。 在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。

Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类。
Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
Exception 分为运行时异常和已检查异常:

    运行时异常(RuntimeException),即不检查异常,通常由应用程序逻辑错误引起,应用程序应避免此类异常。如空指针、数组越界等。
    已检查异常(Checked Exception)在代码中必须显示的进行捕获处理,这是编译期检查的一部分。假设是捕获了异常,然后恢复程序,但现实大多数情况下,都不能恢复。

Error 是程序无法处理的错误,表示运行应用程序中出现了严重的错误,一般会导致程序处于非正常的、不可恢复状态。JVM一般会选择线程终止,不便于也不需要捕获。如:虚拟机自身出现内存溢出(OutOfMemoryError)、栈溢出。

ClassNotFoundException 和 NoClassDefFoundError区别:
首先这两个类都是在类加载的过程中出现的异常。
ClassNotFoundException 类加载器在装载某个类的时候,在所有的类路径下都没有找到这个类,就会报ClassNotFoundException异常。这种情况下既使捕获了这个异常,也是无法恢复程序的,通常在执行下面的方法时容易抛出:
Class.forName()
ClassLoader.loadClass()
ClassLoader.findSystemClass()
也就是说,类加载器在加载阶段找不到类信息,此时如果直接采用反射或者类加载器的loadClass方法去动态加载一个所有classpath里面的都不存在的类,类加载器在运行时的load阶段就会直接抛出ClassNotFoundException异常。
NoClassDefFoundError 属于JVM的ERROR错误,严重级别较高。类加载器在使用阶段找不到类信息,即JVM编译时存在某个类,但是运行时却找不到,就出现了编译和运行不一致,所以就直接抛出了这个ERROR。比如类编译之后被删除了。

Java异常类层次结构图:
image.png
2、异常处理的基本原则
1)尽量不要捕获Exception这样的通用异常,而应该只捕获特定的异常。

try {
    File file = new File("");
    new FileInputStream(file);
} catch (FileNotFoundException e) {
    // ...
}

2)不要生吞异常。

 生吞异常会导致难以排查程序运行过程中出现的问题。或将异常抛出来,最好使用日志框架,详细地输出到日志系统中。

另外需要注意的地方:
尽量不要用一个大的try-catch包住整段的代码。
避免使用 e.printStackTrace() 抛出异常,对于分布式系统,如果发生异常,很难找到异常堆栈轨迹。
输出异常日志时,要考虑避免包含敏感信息,会导致潜在的信息安全问题。比如:用户数据、服务器配置等。

3、异常处理机制
异常捕获 try-catch-finally ,体现了JAVA语言的健壮性
抛出异常 throws 与 throw
两者的区别:

 throw用来在方法体内抛出异常,而throws用来在方法声明处声明异常。

两者的联系:

 如果一个方法中使用了throw关键字抛出了异常,那么要么立即用try/catch语句进行捕获,要么就是用throws进行声明,否则将出现编译错误。然而, 并不是只有使用了throw关键字之后才能使用throws关键字,语法上来说,任何一个方法都可以直接使用throws关键字,抽象方法也可以使用。

实际应用:
1)对于某些特定的业务发现异常情况时,根据自身业务情况,可以采取完善异常时的补偿机制;即当业务处理出现异常时,对当前业务多次进行重试请求。重试请求的策略根据业务的需要决定,当达到重试上限时依然无法成功,或放弃,或通过回调机制通知业务方执行失败。
2)异常信息要尽可能的全面,便于诊断业务异常过程。

异常处理带来的性能开销
1)try-catch 代码段会产生额外的性能开销,影响JVM对代码进行优化;
2)Java每实例化一个Exception,都会对当时的栈进行快照,这个操作相对比较重。如果异常非常频繁,这个开销就不能忽略了。频繁的Exception,也可能会导致服务反应变慢、吞吐量下降。

相关文章
|
23小时前
|
Java 数据库连接 数据库
【JAVA基础篇教学】第六篇:Java异常处理
【JAVA基础篇教学】第六篇:Java异常处理
|
23小时前
|
Java
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
|
1天前
|
存储 安全 Java
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
|
1天前
|
安全 Java API
Java并发设计的7条原则
Java并发设计的7条原则
|
1天前
|
存储 Java API
关于Java异常处理的9条原则
关于Java异常处理的9条原则
|
1天前
|
存储 安全 Java
12条通用编程原则✨全面提升Java编码规范性、可读性及性能表现
12条通用编程原则✨全面提升Java编码规范性、可读性及性能表现
|
1天前
|
Java 数据安全/隐私保护
java中异常处理机制
java中异常处理机制
8 1
|
1天前
|
Java 编译器 开发者
Java一分钟之-继承:复用与扩展类的特性
【5月更文挑战第9天】本文探讨了Java中的继承机制,通过实例展示了如何使用`extends`创建子类继承父类的属性和方法。文章列举了常见问题和易错点,如构造器调用、方法覆盖、访问权限和类型转换,并提供了解决方案。建议深入理解继承原理,谨慎设计类结构,利用抽象类和接口以提高代码复用和扩展性。正确应用继承能构建更清晰、灵活的代码结构,提升面向对象设计能力。
8 0
|
1天前
|
安全 Java
Java一分钟之-访问修饰符与封装原则
【5月更文挑战第9天】本文介绍了Java中的访问修饰符(public, protected, default, private)及其在封装原则中的应用。理解这些修饰符有助于控制类、接口、方法和变量的访问权限,防止过度暴露内部细节。遵循最小权限原则,合理设计接口,并谨慎使用protected,能有效避免常见问题,提高代码的健壮性和安全性。封装是关键,通过使用private修饰成员变量并提供公共访问方式,可减少耦合,增强系统的可维护性。
11 0
|
2天前
|
Java
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
10 0