Java异常与日志01
前言:java开发过程中,异常处理十分正常不过了。接口被调用经过controller、service、dao层,经历了入参校验、业务逻辑处理、封装数据、数据库操作等,经常会出现空指针异常、BadSqlGrammarException异常等等。接下来是我对异常的理解,以及异常在实际工作中是如何处理的。
问题:
1、Java中异常如何分类?
2、怎么处理异常?
3、实际工作中是怎么系统性进行处理的?
异常的分类
Java异常分类结构图(缺一张图,后续补上)
两大类:Error和Exception。
Error是错误,程序中出现Error时,只能人工进行处理,比如OutOfMemoryError(内存溢出)、StackOverFlowError(堆栈溢出)。
Exception是异常,分为checked异常(受检异常)和unchecked异常(非受检异常)。
受检异常,是在代码中显示处理的异常,否者编译会出错,IDE编译工具会报红线。
非受检异常,是运行时异常,他们都继承自RuntimeException,不需要程序进行显示的捕捉和处理,比如常见的空指针异常、数组下标越界异常等,在开发中需要做好边界性检查等等。
异常的处理
因为Error必须人工进行处理,程序无法进行处理,当然也有可能是代码需要优化,比如内存溢出,有可能是代码中使用了过时的方法导致没有即使释放对象,这个早期不容易发现,需要在代码运行一段时间会暴露出来。因此我们常见的能处理的就是受检异常和非受检异常。
1、受检异常的处理
两个关键字,throw、throws。会在一起进行处理,比如在dao层某个方法内部throw异常,在方法签名上throws显示声明向上抛出异常。
throw,制造异常
throws,抛出异常。
2、非受检异常处理
try...catch...finally
(1)只有try不能单独使用,其余任意两两组合。
(2)try代码块中是可能出现异常的代码,需要进行捕捉。
(3)catch代码块中是将捕捉到的异常进行处理,比如打印日志,打印出堆栈信息,方便问题定位。
(4)finally代码块中是进行一些资源释放处理,总是会被执行,比如连接池资源释放、锁资源释放等等。finally代码块中内容在return语句之后进行执行的,执行完后才将return结果进行返回。因此finally语句中最好不要进行赋值处理、不要使用return语句。
实际工作中异常是如何处理的?
我参与的实际工作中是这么处理的。
应用内部:直接抛出异常对象。
应用之间:使用Result对象封装错误码和错误描述信息。
对外提供的开发接口:使用错误码。
具体来说,公司会提供已经封装好底层jar包比如Result对象,方法返回时会返回错误码、错误描述信息,在自身方法中打印出堆栈信息用于问题排查。这样做的好处是,在远程服务调用过程中,如果使用异常抛出的返回方式,一旦调用方没有捕获,就会产生运行时错误,导致程序中断。此外,如果抛出的异常中不添加栈信息,只是new自定义异常并加入自定义的错误信息,对与调用端解决问题的帮助不会太大。如果加入了栈信息,在频繁调用出错的情况下,信息序列化和传输的性能损耗也是问题。
编码约定,推荐方法返回值可以weinull,不强制返回空集合或者空对象等。防止空指针异常一定是调用方的责任,需要调用方进行事先判断。