求你了,不要再在对外接口中使用枚举类型了!,中高级工程师Java开发

2021年09月15日 阅读数:3
这篇文章主要向大家介绍求你了,不要再在对外接口中使用枚举类型了!,中高级工程师Java开发,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。
P_T,

A_B,

P_M

} java


而B系统依赖的AType则是这样的:

public enum AType{git

P_T,

A_B

} 面试


这种状况下,在B系统经过RPC调用A系统的时候,若是A系统返回的AResponse中的aType的类型为新增的P\_M时候,B系统就会没法解析。通常在这种时候,RPC框架就会发生反序列化异常。致使程序被中断。

[](

)原理分析

-----------------------------------------------------------------------

这个问题的现象咱们分析清楚了,那么再来看下原理是怎样的,为何出现这样的异常呢。

其实这个原理也不难,这类RPC框架大多数会采用JSON的格式进行数据传输,也就是客户端会将返回值序列化成JSON字符串,而服务端会再将JSON字符串反序列化成一个Java对象。

而JSON在反序列化的过程当中,对于一个枚举类型,会尝试调用对应的枚举类的valueOf方法来获取到对应的枚举。

而咱们查看枚举类的valueOf方法的实现时,就能够发现,若是从枚举类中找不到对应的枚举项的时候,就会抛出IllegalArgumentException:

public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {markdown

T result = enumType.enumConstantDirectory().get(name);

if (result != null)

    return result;

if (name == null)

    throw new NullPointerException("Name is null");

throw new IllegalArgumentException(

    "No enum constant " + enumType.getCanonicalName() + "." + name);

} 框架


关于这个问题,其实在《阿里巴巴Java开发手册》中也有相似的约定:  

![在这里插入图片描述](https://s2.51cto.com/images/20210912/1631458774191405.jpg)  

这里面规定"对于二方库的参数可使用枚举,可是返回值不容许使用枚举"。这背后的思考就是本文上面提到的内容。

[](

)扩展思考

-----------------------------------------------------------------------

**为何参数中能够有枚举?**

不知道你们有没有想过这个问题,其实这个就和二方库的职责有点关系了。

通常状况下,A系统想要提供一个远程接口给别人调用的时候,就会定义一个二方库,告诉其调用方如何构造参数,调用哪一个接口。

而这个二方库的调用方会根据其中定义的内容来进行调用。而参数的构造过程是由B系统完成的,若是B系统使用到的是一个旧的二方库,使用到的枚举天然是已有的一些,新增的就不会被用到,因此这样也不会出现问题。

好比前面的例子,B系统在调用A系统的时候,构造参数的时候使用到AType的时候就只有P\_T和A\_B两个选项,虽然A系统已经支持P\_M了,可是B系统并无使用到。

若是B系统想要使用P\_M,那么就须要对该二方库进行升级。

可是,返回值就不同了,返回值并不受客户端控制,服务端返回什么内容是根据他本身依赖的二方库决定的。

可是,其实相比较于手册中的规定,我更加倾向于,在RPC的接口中入参和出参都不要使用枚举。

通常,咱们要使用枚举都是有几个考虑:  

一、枚举严格控制下游系统的传入内容,避免非法字符。  

二、方便下游系统知道均可以传哪些值,不容易出错。

不能否认,使用枚举确实有一些好处,可是我不建议使用主要有如下缘由:  

一、若是二方库升级,而且删除了一个枚举中的部分枚举项,那么入参中使用枚举也会出现问题,调用方将没法识别该枚举项。  

二、有的时候,上下游系统有多个,如C系统经过B系统间接调用A系统,A系统的参数是由C系统传过来的,B系统只是作了一个参数的转换与组装。这种状况下,一旦A系统的二方库升级,那么B和C都要同时升级,任何一个不升级都将没法兼容。

我其实建议你们在接口中使用字符串代替枚举,相比较于枚举这种强类型,字符串算是一种弱类型。

若是使用字符串代替RPC接口中的枚举,那么就能够避免上面咱们提到的两个问题,上游系统只须要传递字符串就好了,而具体的值的合法性,只须要在A系统内本身进行校验就能够了。

为了方便调用者使用,可使用javadoc的@see注解代表这个字符串字段的取值从那个枚举中获取。

public Class AResponse{ide

private Boolean success;

/**

*  @see AType 

*/

private String aType;

} 学习



### 最后

手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展示),但均可提供源文件给每位爱学习的朋友

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](https://ali1024.coding.net/public/P7/Java/git)**

![image.png](https://s2.51cto.com/images/20210912/1631458775383760.jpg)