java 自定义异常不终止程序_Java自定义异常(优雅的处理异常)

(本文较长,精华部分直接下拉)

在复杂业务环境下,java自带的异常可能满足不了我们业务的需求, 这个时候我们可以自定义异常来进行对业务异常的处理;

首先,我们先对异常进行基本的解释:

Throwable是所有Java程序中错误处理的父类 ,有两种子类:Error和Exception。

Throwable是所有异常的根,java.lang.Throwable  Error是错误,java.lang.Error  Exception是异常,java.lang.Exception

Error:表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误 ,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。 Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形.应用程序不应该抛出这种类型的对象(一般是由虚拟机抛出).假如出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的。

Exception:表示可恢复的例外,这是可捕捉到的.分为运行时异常,检查性异常.

Java提供了两类主要的异常 :runtime exception和checked exception。

**checked异常:I**O异常,以及SQL异常都是这种异常。 对于这种异常, JAVA编译器强制要求我们必需对出现的这些异常进行catch 。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。 这类异常一般是外部错误,例如试图从文件尾后读取数据等,这并不是程序本身的错误,而是在应用环境中出现的外部错误。

runtime exception 运行时异常:我们可以不处理。当出现这样的异常时,总是由虚拟机接管。

出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。

如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。

抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。

运行时异常是Exception的子类,也有一般异常的特点,是可以被Catch块处理的。只不过往往我们不对他处理罢了。

也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。

如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。

队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。

不应该由于异常数据而影响下面对正常数据的处理。在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。

如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常,或者是通过对异常的处理显式的控制程序退出。

废话不多说,上干货

自定义,运行时异常;

先定义错误码枚举;规范错误集合

/**

* 错误码接口

*/

package com.dyhospital.cloudhis.common.web.exception.reg.exception;

/**

* 错误码接口

* @author jacques

* @version $Id: ErrorCode.java, v 0.1 2016年7月28日 下午3:50:01 zhouzhou

*/

public interface ErrorCode {

/**

* 获取错误码

* @return

*/

String getCode();

/**

* 获取错误信息

* @return

*/

String getDescription();

}

package com.dyhospital.cloudhis.common.web.exception.reg.exception;

/**

* Description:

* User: zhouzhou

* Date: 2019-01-08

* Time: 14:50

*/

import org.apache.commons.lang.StringUtils;

/**

* 业务错误码

* @author zhouzhou

* @version $Id: BusinessErrorCodeEnum.java, v 0.1 2016年4月28日 下午5:44:00 zhouzhou Exp $

*/

public enum BizErrorCodeEnum implements ErrorCode {

/** 未指明的异常 */

UNSPECIFIED("500", "网络异常,请稍后再试"),

NO_SERVICE("404", "网络异常, 服务器熔断"),

// 通用异常

REQUEST_ERROR("400", "入参异常,请检查入参后再次调用"),

PAGE_NUM_IS_NULL("4001","页码不能为空"),

PAGE_SIZE_IS_NULL("4002","页数不能为空"),

ID_IS_NULL("4003","ID不能为空"),

SEARCH_IS_NULL("4004","搜索条件不能为空"),

// 短信相关

SEND_MASSAGE_FAIL("30001","发送短消息失败"),

SEND_MASSAGE_OFTEN("30002","操作发送短消息太频繁,请稍后再试"),

MESSAGE_TEMPLATE_UNDEFINED("30003","短信模板未定义"),

//支付相关

CREATE_PAY_ORDER_FAIL("40001","创建订单支付失败"),

UPDATE_PAY_ORDER_FAIL("40002","更新支付订单失败"),

DEL_PAY_ORDER_FAIL("40003","更新支付订单失败"),

PAY_ORDER_NO_EXISTS("40004","支付订单不存在"),

REFUND_APPLY_NO_EXISTS("40005","退款申请不存在"),

VERIFY_NOT_PASS("40006","验签"),

RES_FAIL("40007","响应失败"),

PAY_CHANNEL_IS_NULL("40008","支付渠道不能为空"),

PAY_CHANNEL_PARAM_ERROR("40009","支付订单渠道参数错误"),

;

/** 错误码 */

private final String code;

/** 描述 */

private final String description;

/**

* @param code 错误码

* @param description 描述

*/

private BizErrorCodeEnum(final String code, final String description) {

this.code = code;

this.description = description;

}

/**

* 根据编码查询枚举。

*

* @param code 编码。

* @return 枚举。

*/

public static BizErrorCodeEnum getByCode(String code) {

for (BizErrorCodeEnum value : BizErrorCodeEnum.values()) {

if (StringUtils.equals(code, value.getCode())) {

return value;

}

}

return UNSPECIFIED;

}

/**

* 枚举是否包含此code

* @param code 枚举code

* @return 结果

*/

public static Boolean contains(String code){

for (BizErrorCodeEnum value : BizErrorCodeEnum.values()) {

if (StringUtils.equals(code, value.getCode())) {

return true;

}

}

return  false;

}

@Override

public String getCode() {

return code;

}

@Override

public String getDescription() {

return description;

}

}

再定义自定义异常类

package com.dyhospital.cloudhis.common.web.exception.reg.exception;

import lombok.Data;

/**

* Description:业务异常类信息

* User: zhouzhou

* Date: 2019-05-08

* Time: 13:35

*/

@Data

public class BizException extends RuntimeException {

private static final long serialVersionUID = -7864604160297181941L;

/** 错误码 */

protected final ErrorCode errorCode;

/**

* 这个是和谐一些不必要的地方,冗余的字段

* 尽量不要用

*/

private String code;

/**

* 无参默认构造UNSPECIFIED

*/

public BizException() {

super(BizErrorCodeEnum.UNSPECIFIED.getDescription());

this.errorCode = BizErrorCodeEnum.UNSPECIFIED;

}

/**

* 指定错误码构造通用异常

* @param errorCode 错误码

*/

public BizException(final ErrorCode errorCode) {

super(errorCode.getDescription());

this.errorCode = errorCode;

}

/**

* 指定详细描述构造通用异常

* @param detailedMessage 详细描述

*/

public BizException(final String detailedMessage) {

super(detailedMessage);

this.errorCode = BizErrorCodeEnum.UNSPECIFIED;

}

/**

* 指定导火索构造通用异常

* @param t 导火索

*/

public BizException(final Throwable t) {

super(t);

this.errorCode = BizErrorCodeEnum.UNSPECIFIED;

}

/**

* 构造通用异常

* @param errorCode 错误码

* @param detailedMessage 详细描述

*/

public BizException(final ErrorCode errorCode, final String detailedMessage) {

super(detailedMessage);

this.errorCode = errorCode;

}

/**

* 构造通用异常

* @param errorCode 错误码

* @param t 导火索

*/

public BizException(final ErrorCode errorCode, final Throwable t) {

super(errorCode.getDescription(), t);

this.errorCode = errorCode;

}

/**

* 构造通用异常

* @param detailedMessage 详细描述

* @param t 导火索

*/

public BizException(final String detailedMessage, final Throwable t) {

super(detailedMessage, t);

this.errorCode = BizErrorCodeEnum.UNSPECIFIED;

}

/**

* 构造通用异常

* @param errorCode 错误码

* @param detailedMessage 详细描述

* @param t 导火索

*/

public BizException(final ErrorCode errorCode, final String detailedMessage,

final Throwable t) {

super(detailedMessage, t);

this.errorCode = errorCode;

}

/**

* Getter method for property errorCode.

*

* @return property value of errorCode

*/

public ErrorCode getErrorCode() {

return errorCode;

}

}

接下来是使用类, 直接抛出异常枚举, 或者自定义其message

if (billInfo != null) {

throw new BizException(BizErrorCodeEnum.SEARCH_IS_NULL);

}

if (billInfo != null) {

throw new BizException("错误啦");

}

另外, 全局抓取异常向前端返回固定json格式的全局异常配置如下:

@ControllerAdvice

public class ControllerAdviceProcessor {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired

protected MessageSource messageSource;

@ExceptionHandler(Exception.class)

@ResponseBody

public GenericResponse> handleException(HttpServletRequest request, Exception ex) {

String code = "500";

if (ex instanceof HttpMessageNotReadableException) {

code = "400";

} else if (ex instanceof HttpRequestMethodNotSupportedException) {

code = "999";

}

String msg = null;

if (ex instanceof BizException) {

BizException bizException = (BizException) ex;

msg = bizException.getMessage();

code = bizException.getErrorCode().getCode();

} else if (ex instanceof AccessDeniedException) {

msg = "无权限访问";

code = "403";

}

if (msg == null) {

msg = ex.getMessage();

}

GenericResponse> resp = new GenericResponse<>();

resp.setCode(code);

resp.setMessage(msg);

logger.error("code: " + code + "  msg: " + msg, ex);

return resp;

}

}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值