一、前言
异常处理是平时开发过程中程序员必备一种技能,也可以说是一种思想常态。为了处理能够在程序中处常, 必须要研究程序中出现的错误和问题。异常情况主要主要有以下几种:
1、用户输入错误:这是最常见的错误,用户不按照程序要求去执行输入。一般情况下这种问题在前端和后端的有效控制就可以规避。
2、设备错误:硬件问题虽然并不常见,但是也需要谨慎对待,硬件的种类包括很多,通俗的比如打印机坏了、
3、物理限制:这个比如磁盘满了,尤其是日志输出较多或者数据文件较多的应用,磁盘空间不够是常态,扩容只是一种临时手段,要考虑定时清理和数据转移存储已近磁盘的使用的监控。
4、代码错误:这也是平时接触最频繁的一块儿。也是接下来主要分析的一点。
在Java程序设计中,异常分类以及异常处理一直都是Java工程师需要具备基础知识。
二、详述
所有的异常都来Throwable,下一层即分解为Exception与Error两大类。来看看下面这个类图结构:
Exception与Error比较分析:
相同点:都继承了Throwable类,在Java中只有继承了Throwable类型的实例才可以抛出throw或者捕获(catch).
不同点:Exception是程序正常运行中,可以预料的意外情况,并且应该被捕获,并进行相应处理。Exception又分为可检测的(checked)异常,比如:I/O异常,在编写代码时就可以捕获处理;不检查(unchecked)异常也救是RuntimeException(运行时异常),比如:NullPointerException(空指针异常)。可检查异常必须在代码中显示的进行捕获或者抛到调用层处理,而不检查异常通常可以通过编码避免,不强制捕获。运行时异常的出现,那么一定是你的代码有问题。
Error是只在正常情况下,不大可能出现的情况,绝大多数的Error都会导致程序的处于非正常的,不可恢复的状态,比如常见OOM,出现Error说明了程序不在正常状态下。
异常处理基本方式:异常处理关键字try-catch-finally块、throw、throws,try-catch-resource
如何处理异常:
1、try-catch尽量不捕获类似Exception这样的通用异常,应该捕获特定异常。try-catch块尽量短小,捕获应该捕获的代码段。如果你在看别人的代码大段大段的捕获Exception的时候不顺眼的时候,恭喜你,你已经开始有意识正确处理异常了
2、不要生吞异常,不要捕获异常不处理,只打印堆栈信息。如果上层还有调用,那么的你的异常将不会被发现。捕获异常要么捕获抛出异常,及时不处理也要切记打印必要的日志信息。实践证明,这种不处理结果会是一个大坑。
3、在不明确是否要捕获抛出异常时,可以尝试捕获抛出异常,交给调用层根据业务要求是否要处理,这样能更清晰处理思路。在平时开发中,避免不了会有公用的组件方法,如果你此时你捕获处理了方法,可能就不适用于其他调用方。
4、尽量不要用try-catch代码块来控制代码流程。
三、性能角度分析
在Java中,try-catch代码段会产生额外的性能开销,它往往会影响JVM对代码进行优化,代码段越大影响效率越会明显。而且在每实例化一个Exception时,都会对当时的栈进行快照。如果发生非常频繁,这个开销是不能被忽略的。
拓展:
1、Java1.7新增捕获特性try-with-resources
2、NoClassDefFoundError与ClaseeNotFoundException的区别:
NoClassDefFoundError 和 ClassNotFoundException 都是由于在 CLASSPATH 下找不到对应的类而引起的。 当应用运行时没有找到对应的引用类就会抛出 NoClassDefFoundError,当在代码中通过类名显式加载类(如使用 Class.forName())时没有找到对应的类就会抛出 ClassNotFoundException。再稍微详细点来说,NoClassDefFoundError 表示该类在编译阶段可以找到,但在运行时找不到了,另外有时静态块的初始化过程也会导致 NoClassDefFoundError。而 ClassNotFoundException 一般发生在通过反射或者 ClassLoader 依据类名加载类时类不存在。此外 NoClassDefFoundError 是 Error,是不受检查类型的异常;而
ClassNotFoundException 是受检查类型的异常,需要进行异常捕获,否则会导致编译错误。再深入来说,NoClassDefFoundError 是链接错误,发生在 JVM 类加载流程的链接阶段,当解析引用的时候找不到对应的类就会抛出 NoClassDefFoundError;而 ClassNotFoundException 一般发生在类加载流程的加载阶段。