怎么高雅的处理反常 Java言语反常剖析
一、什么是反常。
Java。言语依照过错严重性,从 throwale 根类衍生出 Error 和 Exception 两大派系。
Error(过错):
程序在履行进程中所遇到的。硬件。或。操作体系。的过错。过错对程序而言是丧命的,将导致程序无法运转。常见的过错有内存溢出,jvm 虚拟机本身的非正常运转,calss 文件没有主办法。程序本生是不能处理过错的,只能依托外界干涉。Error 是体系内部的过错,由 jvm 抛出,交给体系来处理。
Exception(反常):
程序正常运转中,能够意料的意外状况。比方数据库衔接中止,空指针,数组下标越界。反常呈现能够导致程序非正常停止,也能够预先。检测。,被捕获处理掉,使程序持续运转。Exception(反常)依照性质,又分为编译反常(受检反常)和运转时反常(非受检反常)。
◦编译反常:
又名可查看反常,一般时由语法错和环境要素(外部资源)形成的反常。比方输入输出反常 IOException,数据库操作 SQLException。其特点是,Java 言语强制要求捕获和处理一切非运转时反常。经过行为规范,强化程序的健壮性和安全性。
◦运转时反常:
又名不查看反常 Run。ti。meException,这些反常一般是由程序逻辑过错引起的,即语义错。比方算术反常,空指针反常 NullPointerException,下标越界 IndexOutOfBoundsException。运转时反常应该在程序测验期间被露出出来,由。程序员。去调试,而防止捕获。
二、处理反常方法。
代码中,咱们最常见到的处理反常的方法便是:try-catch。
try { // 事务逻辑 } catch (Exception e) { // 捕获到反常的逻辑 }。
或者是再进一步区别下反常类型:
try { // 事务逻辑 } catch (IOException ie) { // 捕获到IO反常的逻辑 } catch (Exception e) { // 捕获到其他反常的逻辑 }。
三、怎么抛出反常。
咱们一般能够用抛出反常的方法来操控代码流程,然后在网关处一致catch反常来回来过错code。这在必定程度上能够简化代码流程操控,如下所示:
Override publ。ic。UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); if (Objects.isNull(userDO)) { throw new RuntimeException("用户不存在"); //用户不存在抛出反常 } return userDO.toVo(); }。
上面这种抛出反常的方法,尽管简化了代码流程,可是在存在多种过错场景时,没有办法细分详细的过错类型。如:用户不存在的过错、用户没有权限的过错;
聪明如你,必定想到了自界说反常,如下:
Override public UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); if (Objects.isNull(userDO)) { throw new UserNo。tF。oundException(); //用户不存在抛出对应反常 } if(!checkLicence(userDO)) { throw new B。ad。LicenceException(); //用户无权限抛出对应反常 } return userDO.toVo(); }。
的确,自界说反常能够处理过错场景细分的问题。进一步的,咱们能够对体系流程不同阶段、不同事务类型别离自界说反常,但这需求自界说很多的反常;
四、怎么高雅的抛出反常。
上面的方法,能够区别出过错场景了,可是还存在一些缺陷。如:可读性差、需求界说很多的自界说反常;
那咱们下面就去优化上面的问题;
用断语添加代码的可读性;
Override public UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); Assert.notNull(userDO, "用户不存在"); //用断语进行。参数。的非空校验 return userDO.toVo(); }。
断语尽管代码简练、可读性好,可是缺少像上述自界说反常相同能够清晰区别过错场景,这就引出咱们的究极计划:自界说断语;
自界说断语;
咱们用自界说断语的方法,归纳上面自界说反常和断语的长处,在断语失利后,抛出咱们制定好的反常。代码如下:
•自界说反常根本类。
Get。te。rSetterpublic class BaseException extends RuntimeException { // 呼应码 private IResponseEnum responseEnum; // 参数。信息。private Object[] objs; public BaseException(String message, IResponseEnum responseEnum, Object[] objs) { super(message); this.responseEnum = responseEnum; this.objs = objs; } public BaseException(String message, Throwable cause, IResponseEnum responseEnum, Object[] objs) { super(message, cause); this.responseEnum = responseEnum; this.objs = objs; }}。
•自界说断语。接口。
public interface MyAssert { /** * 创立自界说反常 * * pa。ram。objs 参数信息 * return 自界说反常 */ BaseException newException(Object... objs); /** * 创立自界说反常 * * param msg 描绘信息 * param objs 参数信息 * return 自界说反常 */ BaseException newException(String msg, Object... objs); /** * 创立自界说反常 * * param t 接纳验证反常 * param msg 描绘信息 * param objs 参数信息 * return 自界说反常 */ BaseException newException(Throwable t, String msg, Object... objs); /** * 校验非空 * * param obj 被验证目标 */ default void assertNotNull(Object obj, Object... objs) { if (obj == null) { throw newException(objs); } } /** * 校验非空 * * param obj 被验证目标 */ default void assertNotNull(Object obj, String msg, Object... objs) { if (obj == null) { throw newException(msg, objs); } }}。
上述代码咱们能够看出根本规划,便是在咱们自界说断语失利后抛出咱们自界说反常。
下面是详细的完成事例:
•自界说事务反常类,承继自反常根本类。
public class BusinessException extends BaseException { public BusinessException(IResponseEnum responseEnum, Object[] args, String msg) { super(msg, responseEnum, args); } public BusinessException(IResponseEnum responseEnum, Object[] args, String msg, Throwable t) { super(msg, t, responseEnum, args); }}。
•呼应code枚举接口界说。
public interface IResponseEnum { /** * 回来code码 * * return code码 */ String getCode(); /** * 回来描绘信息 * * return 描绘信息 */ String getMsg();}。
•自界说事务反常类断语界说,完成自界说断语失利后对应的自界说反常的界说;
public interface BusinessExceptio。nAs。sert extends IResponseEnum, MyAssert { Override default BaseException newException(Object... args) { return new BusinessException(this, args, this.getMsg()); //断语失利后,抛出自界说反常 } Override default BaseException newException(String msg, Object... args) { return new BusinessException(this, args, msg); //断语失利后,抛出自界说反常 } Override default BaseException newException(Throwable t, String msg, Object... args) { return new BusinessException(this, args, msg, t); //断语失利后,抛出自界说反常 }}。
•用枚举的方法,替代BadLicenceException、UserNotFoundException自界说反常。
public enum ResponseEnum implements IResponseEnum, BusinessExceptionAssert { BAD_LICENCE("0001", "无权拜访"), USER_NOT_FOUND("1001", "用户不存在"), ; private final String code, msg; ResponseEnum(String code, String msg) { this.code = code; this.msg = msg; } Override public String getCode() { return code; } Override public String getMsg() { return msg; }}。
运用实例。
自界说断语失利抛出自界说反常。
Override public UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); ResponseEnum.USER_NOT_FOUND.assertNotNull(userDO); //自界说断语失利抛出自界说反常 return userDO.toVo(); }。
网关处一致catch反常,辨认反常场景。
public static void main(String[] args) { Use。rS。ervice userService = new UserServiceImpl(new UserMapperImpl()); UserController userController = new UserController(userService); try { UserVO vo = userController.queryUser(2L); //履行事务逻辑 } catch (BusinessException e) { System.out.println(e.getResponseEnum().getCode()); //呈现反常,过错code:1001 System.out.println(e.getMessage()); //呈现反常,过错msg:用户不存在 } }。
五、怎么高雅的处理反常。
网关处一致处理反常,这归于惯例操作,这儿不再赘述,简略举例如下:
ControllerA。dvi。cepublic class BusinessExceptionHandler { ExceptionHandler(value = BusinessException.class) ResponseBody public Response handBusinessException(BaseException e) { return new Response(e.getResponseEnum().getCode(), e.getResponseEnum().getMsg()); //一致处理反常 }}。
综上,咱们选用自界说断语的方法,结合了断语的可读性高的优势和自界说反常区别过错场景的优势。而且,有新增的过错场景,咱们只需求在过错码枚举中新增对应枚举即可。
审阅修改 黄宇。
内容来源:https://artdesignphuong.com/app-1/banh số 4,http://chatbotjud-teste.saude.mg.gov.br/app-1/bet-365-levantamento-banco-do-brasil
(责任编辑:人文)