开发中异常的处理和技巧|Java 开发实战

374 阅读5分钟

本文正在参加「Java主题月 - Java 开发实战」,详情查看 活动链接

前言

开发也有几年时间,其实没什么大的实战经验,做的不是什么高并发,也不是什么大公司,平时写也是业务逻辑,很多时候都是自己写,对代码的对错思考的也不多,有人说代码写的能跑就行,在这个这个需求我很简单,明天就要上线的背景下,我很多时间都是贫血模式在写,最近对代码和写法上觉得自己之前很多地方写的不好,借此机会总结一下,都是开发中真正遇到的问题。本文先总结异常的处理和使用。

异常的处理

之前没把异常看的很重要,一般try-catch就放着不管,很多时候一个快捷键把有可能异常的代码try-catch包起来就完了,把业务代码一写,很多时候就很少管catch里面的异常。最多日志输出出异常。

背景

最近在做一个项目的时候,因为我写的模块偏API调用,所以我写的模块是不需要单独运行的,是直接在maven里面当成依赖jar被其他启动的项目依赖调用。对异常的处理,我开始也是这样直接打印输出日志。如下: image.png

问题1

在其他被依赖的模块调用我的API出现了异常,但是异常信息没有直接打印出来,导致定位不到问题。

解决1

第一个直观的认为我的这个项目是jar包供别人依赖,那么我自己打印的日志依赖我的项目是看不到的,所以我需要把异常往外层抛出去。故需要改成这样。 image.png 就是把异常直接抛出去,这里注意一个小问题,如果你这个方法经过好几个方法层层调用出去的,比如你这个异常在a方法里面,被c方法调用,c方法又被d方法调用,那么在c的方法里面如果直接处理了异常没有往外抛,那么在d就是最终调用方是看不到a方法抛出的异常的。

问题2

项目启动继续跑,能捕获到异常,但是我这个任务是for循环执行的,所以如果一个记录有问题,我需要跳过当前记录,继续执行下一个任务,就是不能让一个记录错误,影响这个任务后面的其他任务,在最外面的调用层我直接这样写的: image.png 有个问题就是我直接在最外层把异常抛给jvm虚拟机了,我没有在最终调用方处理当前异常,那么循环的过程中一旦有一个记录出错,我整个任务就停了。跟我的业务不符合。需要修改最终调用方法对异常的处理。

解决2

需要在最终调用放捕获异常,然后把异常日志输出,打印出异常的类型和堆栈内容,让代码继续走后续的逻辑。 image.png 注意:当发生异常的时候你是需要抛出还是捕获,是需要继续执行后面的逻辑,还是让代码从异常这停止当前任务,在开发的时候需要注意。下面简单总结下异常的使用场景和注意逻辑。

异常不能代替测试

举例:比如你需要判断一个对象是否为空,如果不为空截取前10个字符。 image.png 不能不判断非空直接异常把语句包起来来代替测试。 image.png

不要过分细化和把确认没有异常的代码包在try里面

不要把确认都有异常的代码分开成多个try-catch代码块,但是也别把确认没有异常的代码包到try-catch里面我见过很多人从一个方法的第一行到最后一行全部包在try-catch代码块里面,其实里面就一行代码可能出现异常。 image.png

利用异常层次结构

  • 不要只抛出RuntimeException异常,需要找更加合适子类或者去创建适合自己的异常类。
  • 不要只捕获Thowable异常,这种会使代码可读性和可维护性变差
  • 可以将一种异常转换成更加合适精确的的异常

在检查异常的时候,严格要求比不做处理好

当监测到错误的时候,比如在栈为空的时候,Stack.poll()弹出的时候如果有异常我们是返回null?还是抛出一个异常?好的思路是:在程序的前面就抛出EmptyStackException比在程序的后面会报空指针NullPointerException异常更好。

不要害怕往外传递异常

我在开发中也有这种顾虑,我觉得在我这一层应该捕获全部的异常,其实传递异常比捕获异常更好,我上文的例子就是一个典型的传递比捕获异常更好的做法,我做成了在API层捕获异常,而不是在API层把异常抛出去,让最外层(高层)的方法通知用户发生了异常错误,或者放弃不成功的命令更合适。总结就是早抛出,晚捕获

总结

原本还想总结下其他开发中注意的东西,异常就写了这么多,如果有时间我下次我再总结我实战开发中遇到的小问题。本文主要总结了对异常在不同情况下的不同处理,和处理异常的一些小细节。