## 异常处理规范

- 统一使用KDException，可自定义子异常。
- 只catch需要处理的异常，其它放过 (任其往上抛)。
  - catch异常后，再往上抛出异常，通常不需要记录日志。
  - catch异常后，未往上抛出异常，务必记录日志。
- UI显示的异常信息，应是业务语义，让用户知道下一步该怎么处理。



## KDException

**苍穹所有异常均为KDException或继承自KDException。**

```java
public class KDException extends RuntimeException {
    
    public KDException(ErrorCode errorCode, Object... args)       
    
        
    public KDException(Throwable cause, ErrorCode errorCode, Object... args) 
   
    ...
}
```



## ErrorCode

错误码是全局唯一的，用于定位错误和反馈提示信息，包含错误代码和提示信息。

```java
public ErrorCode(String errorCode, String message)
```



**1) ErrorCode参数**

- errorCode：错误代码，产品全局唯一，格式：**产品云.应用.错误码**，产品云、应用均为小写，错误码与java变量名同(驼峰式)。
- message：默认的错误信息，可用%s模版参数(参见String.format)，在抛KDException时传入值(args)。



每个应用应统一定义异常，如`FIGLErrorCode`：

```java
final static ErrorCode voucherNotInCurrentPeriod = new ErrorCode("fi.gl.voucherNotInCurrentPeriod", "凭证%s不在当前期间，不可编辑。");
```

`fi.gl.voucherNotInCurrentPeriod`为错误代码，其错误信息是多语言的，由多语言资源进行配置。

如：

- 中文：fi.gl.voucherNotInCurrentPeriod=凭证%s不在当前期间，不可编辑。
- 英文：fi.gl.voucherNotInCurrentPeriod=The voucher %s cannot be modified because it is not in the current period.

ErrorCode的第二个参数msg是缺省提示信息，未配置多语言时提示的信息。



**2) 抛异常使用ErrorCode**

```java
// xxx为凭证编码
throw new KDException(FIGLErrorCode.voucherNotInCurrentPeriod,"xxx")
    
// 中文异常信息为：凭证xxx不在当前期间，不可编辑。
```



**3) 应用错误码类定义示范**

```java
public class FIGLErrorCode {
	
	private static ErrorCode create(String code, String message) {
		return new ErrorCode("fi.gl." + code, message);
	}

	public final static ErrorCode voucherNotInCurrentPeriod = create("voucherNotInCurrentPeriod", "凭证%s不在当前期间，不可编辑。");

	public final static ErrorCode nextPeriodNotSetted = create("nextPeriodNotSetted", "下一期间%s未设置。");
	
	//TODO ....开发在此添加其它错误码定义

}
```



## 异常用法示例

**1) 抛业务异常**

```java
if (!isInCurrentPeriod) {
	throw new KDException(FIGLErrorCode.voucherNotInCurrentPeriod, voucherNumber);
}
```

**2) catch业务异常**

业务异常，是指业务逻辑校验抛出的异常。

仅catch要关注的异常：

```java
try {
	
	callMyBizMethod();
	
} catch (KDException e) {
	
	// 在这里处理你关注的异常
	ErrorCode errorCode = e.getErrorCode();
	if (FIGLErrorCode.voucherNotInCurrentPeriod.equals(errorCode)) {
		// 在这里处理你的业务：异常收尾处理
		// ...
	}
	
	// 放过不关注的
	throw e;
}
```

**3) catch所有异常**

业务异常外，其他异常统称为系统异常，如ConnectException、TimeoutException等。

系统异常有两种处理方式：

- 不理会，让其往上抛异常，由外层调用处理。
- 封装为业务异常，再往上抛，如下例。

```java
try {	
	doMyJob();	
} catch (KDException e) {
	// 业务异常，往上抛。
	throw e;
} catch(Exception e){
    // 封装系统异常为业务异常
    throw new KDException(e, FIGLErrorCode.doMyJobFailed, "jobname", e.getMessage());
}
```

