什么情况下需要抛出异常,什么情况下需要catch住异常?
站在代码开发者的角度
在进行异常处理的时候,可以try catch住这些异常,然后在catch那里打印错误日志,方便定位问题。
还有一种在发现异常的时候,可以把这部分异常抛出来,让上游调用方可以知道这里会出现哪些异常,上游调用方在获取到这些异常时,可以根据业务特点来处理这部分异常。
站在调用方的角度
在调取其他模块接口的时候,需要知道被调用方接口有哪些异常,调用方根据业务特点来处理这部分异常。异常有2种处理方式:
1.try catch住这些异常,其他接口的异常并不影响当前接口
2.抛出异常,其他接口异常后,当前接口也异常。具体哪种处理方式需要根据自己的业务特点选择。
总体来说
如果你的服务就是请求链路的最上游或者你写了一个没有人调用的接口,你根据自己的业务特点catch住异常是没有问题的。
如果你的代码有其他人调用,那么出现异常你需要把异常抛出来。
代码讲解之前先解释一些名词,不要因为这些名词而引起对代码理解的偏差;
服务A在接收到前端请求后,需要调取接口B查询一部分数据,需要调取接口N查询一部分数据,然后进行数据拼装返回。这叫请求链路。
对于接口B,接口A就是接口B的接口调用方,接口B的上游就是接口A。
前端想要获取数据,那么接口A就是最上游。接口A没有后端调用者。接口B或者接口N,都有调用者,调用者是接口A。
业务场景:
用户在外卖商品页面选择完商品后,点击提交订单,后端服务需要保存订单数据和将商品的库存数量减1。
接下来看代码:
这个代码里面包含2部分逻辑,逻辑1是保存订单数据,逻辑2是更新商品库存数据。
问题:
负责开发更新商品库存接口的同学把异常给try{}catch{}住了。当用户点击提交订单时,请求落到了订单服务,OrderService.saveOrder()方法将订单数据保存后,调取更新商品库存数量的接口,更新商品库存数量的接口异常了,商品库存数量并没有更新成功,但是因为异常try{} catch{}住了,对于订单服务而言,订单服务又不知道商品库存接口异常了,返回给用户保存成功,但是现在商品库存数据却没有保存成功;
发现问题后,让商品库存的同学把代码修改下,把异常抛出来,不要自己把异常处理(吃)了。
代码变成如下形式,当更新商品库存数据异常后,订单服务也抛出异常,让用户知道提交订单异常,用户可以选择再次下单。
业务场景:
这个是商品详情页,包含商品数据和评价数据。 如果评价数据可以查询到就展示,查询评价数据异常时,页面降级不展示评价数据。
接下来看代码:
这个代码里面包含2部分逻辑,逻辑1是查询商品数据,逻辑2是查询评价数据。因为GoodsService的getGoodsById()方法将查询评价数据接口try{}catch{}住了,查询评价数据接口异常时,并不会影响查询商品数据接口的稳定性。
总结:
如果这个方法在调用链路的下游,有其他系统去调用这个方法时,出现异常了需要将异常抛出来;上游调用方可以根据自己的业务特点选择抛出异常或者try{}catch{}住异常。
接下来看另一个场景:
业务场景:
用户下单,取消订单或者其他订单关联的业务,需要将订单状态流转数据保存到订单日志表中,当订单数据出现问题时,通过订单日志表,很方便的可以定位出问题。
接下来看代码:
创建订单和取消订单主要包含3部分逻辑:
1.保存或者更新订单数据
2.将订单操作日志数据写入到数据库中
3.如果订单操作日志数据写入数据库异常时,发送一条MQ消息,让MQ消息的重试机制保证日志数据写入成功。
问题:
OrderLogService除了OrderService调用外,不会有其他类会调用。OrderService对OrderLogService的异常处理逻辑一样,处理逻辑为发送一条MQ消息,通过MQ消息的重试机制保证日志数据写入成功。一个异常,超过2个方法处理(修改订单未实现),而且处理逻辑一样。 异常不如让OrderLogService自己来处理。
将代码改成如下形式:如果操作日志数据写入失败后,让OrderLogService内部自己处理。
这样做的好处:
1.OrderService代码简洁,不用再去处理OrderLogService异常;
2.现在日志数据写入失败后,OrderLogService会发送一条MQ消息。 以后需要修改异常处理方式,只需要修改OrderLogService里面的逻辑就好。
总结:
如果这个方法只有同一个系统的接口去调用,而且内部对这个异常有相同的处理逻辑,出现异常了可以让这个方法将异常处理掉,这样其他调用方就不需要处理异常了
#大厂##面试题目#