Java中使用枚举(enum)还是常量?枚举!

这里先说结论:对于一组关联的数值,出于对数据安全的考虑,我们选择使用enum。

问题

定义表结构的时候经常会碰到一类字段:状态 ( status 或者 state ) 、类型 ( type ) ,而通常的做法一般是:

  • 数据库 中定义 tinyint 类型。
    比如:status tinyint(1) NOT NULL COMMENT ‘订单状态 1-待支付;2-待发货;3-待收货;4-已收货;5-已完结;’
  • Java 实体类 中定义 Short 类型。
    比如:private Short status

然后项目中可能会充斥着下面这样的代码:

order.setStatus((short) 1);
 
if (order.getStatus() == 1) {
    order.setStatus((short) 2);
}
 
if (order.getStatus() == 4) {
    order.setStatusName("已收货");
}

这都是些什么魔鬼数字啊,没有注释根本没法看,如果手滑可能状态就设错了,而且不好排查是在哪处赋值的。

改进方案是用 常量 ,但是又会产生另一种效果:

public static final Short WAIT_PAY = 1;
 
if (WAIT_PAY.equals(order.getStatus())) {
    // 混用了解下
    order.setStatus((short) 2);
}

定义常量对使用者没有约束力,仍然可能会被程序员无视,而直接使用数字。

这时候就该 枚举 出场了,枚举 的本质就是 类 + 常量 ,可以使用 枚举 来定义 一组 相关的元数据 ( 值、描述及其他必要信息 ) ,使用 枚举 类型不仅减小了数据维护 ( 比如调整了值的定义 ) 的成本,还加强了代码的 约束力 。

我们在实体类(DO/DTO/BO/VO/PO)和方法参数中,统一使用枚举类型的属性来保存有固定取值的字段。

要做到上面这一点,有下面三个地方要注意

  • 把接口的参数转化为枚举类型
  • 把接口返回的枚举类型转为String
  • 把枚举类型保存到数据库中

把接口的参数转化为枚举类型

Spring 默认使用Bean接收枚举参数时支持 字面量,这也是我们常见的做法。

如下:

@Data
public class UserCommand {

    private String name;

    private Gender gender;

    private String email;
}
    @ApiOperation("添加用户")
    @PostMapping("/users")
    public User users(User command){
        User user = new User();
        BeanUtils.copyProperties(command,user);
        return user;
    }

在这里插入图片描述注意这种方式不支持枚举的ordinal值

把接口返回的枚举类型转为String

《阿里巴巴Java开发手册》将接口中枚举的使用分为两类,即 接口参数和接口返回值,并规定: 接口参数可以使用枚举类型,但接口返回值不可以使用枚举类型(包括含枚举类型的POJO对象)。
  这个主要是对dubbo等使用tcp协议的rpc接口调用来说的,为了避免序列化异常;对于spring cloud等使用http协议的框架,没有此限制。
  jackson 解析枚举 时,默认会返回字面量( MALE,FEMALE)。也可以通过@JsonValue指定要返回的属性:

public enum Gender {
	MALE(0,"男"),FEMALE(1,"女"),UNKOWN(2,"未知");
	
    private Integer id;
    private String name;
	
	private Gender(Integer id,String name) {
		this.id = id;
		this.name = name;
	}
	private Gender(Integer id) {
		this.id = id;
	}
	
	private Gender(String name) {
		this.name = name;
	}
	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@JsonValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
}

把枚举类型保存到数据库中

MyBatis内置了两个枚举转换器分别是:org.apache.ibatis.type.EnumTypeHandler和org.apache.ibatis.type.EnumOrdinalTypeHandler。

  • EnumTypeHandler
    这是默认的枚举转换器,该转换器将枚举实例转换为实例名称的字符串,即将SexEnum.MALE转换MALE。
  • EnumOrdinalTypeHandler
    顾名思义这个转换器将枚举实例的ordinal属性作为取值,即SexEnum.MALE转换为0,SexEnum.FEMALE转换为1。

使用时,修改mapper的xml文件:

<result column="status" property="orderStatusEnum"
                typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
<insert id="insert" parameterType="com.example.entity.OrderInfo">
        INSERT INTO
            order_test
            (status)
        VALUES (
            #{orderStatusEnum, typeHandler=com.example.typeHandler.EnumOrderStatusHandler, jdbcType=INTEGER}
        )
    </insert>

当然,也可以自定义枚举类型转换器,这里不详述。

注意:
保存枚举的ordinal值时,给枚举增加取值要加在最后,在中间插值会导致数据前后不一致。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiegwei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值