缘起:
因为最近准备对我第一个SSH项目进行重写和优化,在做这件事之前,我需要反思整理这个项目在之前的开发过程中忽略的地方。并期望在这次开发中正视问题,发现问题。
本文目标:
1、搞清楚为什么使用异常;
2、Java异常的结构;
3、Java异常的使用场景和使用方法;
4、异常使用的技巧以及应该规避的错误;
5、实际基于JavaWeb及框架开发时,异常的处理方式,抛出还是捕捉,在哪里捕捉/处理的问题;
正文:
1、为什么要使用异常?
在开发过程中,自己心里一直有一个疑问。如果要读一个文件,简单的方式是首先判断这个文件是否存在,然后在读取。这就是完整的流程,为何非要定义一个
FileNotFoundException的异常类。经过资料搜寻和自己经验,得出以下结论:
(1)异常表示的是“运行中”出现的错误。类似“
if(文件存在)使用文件”这种模式,非原子性,完全可能在判断后,别人删除文件,导致运行中出现错误,这个事不可预料的。
(2)使用“
if(文件存在)使用文件”这种模式将导致程序中出现很多判断语句,不能专注逻辑流程,使用异常将简化这个流程。
(3) 强制程序员处理可能出现的错误。(来自知乎)
(4)可以返回方法栈,跟踪错误的路径。(来自知乎)
2、Java异常结构
2.1Throwable结构
(1)Error
(2)Exception
(2-1)RuntimeException
(2-2)Exception
2.2受检异常和非受检异常的理解
checked与unchecked的概念理解:
checked: 一般是指程序不能直接控制的外界情况,是指在编译的时候就需要检查的一类exception,用户程序中必须采用try catch机制处理或者通过throws交由调用者来处理。这类异常,主要指除了Error以及RuntimeException及其子类之外的异常。
unchecked:是指那些不需要在编译的时候就要处理的一类异常。在java体系里,所有的Error以及RuntimeException及其子类都是unchecked异常。再形象直白的理解为不需要try catch等机制处理的异常,可以认为是unchecked的异常。
3、异常的使用场景;
3.1对于JavaAPI或者框架里面抛出的异常;
以上两种情况,在处理时毫无含糊,自己的程序用到这些api的时候,必须要向上传递或者catch处理。但是对于web程序,我自己的理解是尽量不要在底层catch。这样会隐藏某些程序错误,让这些错误“烂在程序的日志里”。
我认为处理的方法是:
第一,是规避异常,做妥善的处理。
第二,实在无可避免的情况,要向上抛到至少service层。
第三,由上层转义,在表现层提示,由用户来决定是否继续执行。
3.2对于自己设计的程序使用“受检异常”还是“非受检异常”(不具备普遍意义)
自己程序设计到异常的时候。我认为模块内部的异常可以设计成“非受检异常”。但是如果是共同项目,或者模块要拿给别人使用的。应该设计成受检异常,提醒调用者处理可能出现的异常情况;