用魔法打败魔法——解决Java代码中的魔法值

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

0. 问题

在日常代码编写过程中,在判断条件中经常会使用如下语句:

if(!"1".equals(MapUtils.getString(user, "role"))){
    ...
}else{
    ...
}
复制代码

该语句在程序运行时是正常的,但是却违反了开发规范,如果IDEA中使用了阿里巴巴Java开发规范插件,则此处会有提示:“魔法值【"1"】”、魔法值【"role"】。

image.png

点开规范提醒的详细信息,可以看到:不允许任何魔法值(即未经定义的常量)直接出现在代码中。

image.png

1. 魔法值

1.1 魔法值概念

魔法值,也叫做魔法数值、魔法数字,通常是指在代码编写时莫名出现的数字,无法直接判断数值代表的含义,必须通过联系代码上下文分析才可以明白,严重降低了代码的可读性。

除数字之外,代码中作为key值的常量字符串也被认为是魔法值,尽管其表示含义比数值较为清晰,但是仍然会产生不规范问题。

1.2 为什么会出现魔法值

在对数据的处理过程中,为了充分利用机器的存储性能,数据库存储时往往使用更加简单的数值来代表复杂的名词含义,如使用1、2、3、4等数值来代表状态信息,0、1来代表false和true等。

由于数据库中存储的是数值数据,因此后端代码在与数据交互时,对数据进行验证同样需要使用数值进行判断,这就造成了后端代码中大量[魔法值]的存在。

这种编写方式不会产生任何执行错误,代码也是简洁的,但是代码含义非常不直观、且review和后期维护成本是巨大的。

1.3 魔法值的潜在危害

除了代码阅读不直观外,魔法值还可能造成以下问题的发生:

  • 数值使用不规范,多处使用不统一,修改时工作量大且容易遗漏
  • 数值使用错误,程序不产生异常,但业务逻辑数据出现问题
  • 常量字符串作为key时拼写错误,key值无对应value,导致数据异常或缓存无法命中

2. 魔法值解决方法

2.1 静态常量方法

仅在当前类中使用或在方法内部使用的值,可以通过定义静态常量的方式来避免魔法值的出现。 如下使用定义静态常量的方式替换掉代码中的魔法值:

public static final String ADMIN_ROLE = "1";
public static final String _NAME_ = "name";
if(!ADMIN_ROLE.equals(MapUtils.getString(user, _NAME_))){
    ...
}else{
    ...
}
复制代码

静态常量定义时约定名称的所有字母都要大写,以此表示该标识为不变常量,如此这般使用之后,IDEA中的阿里巴巴规范便不再提示问题。

2.2 枚举类方法

枚举类是另一种更规范的消除魔法值的方法,使用时需要定义一个枚举类,并为类定义属性和构造方法等。枚举类能够约束静态常量的定义规范,提供统一格式的静态常量值,在统一异常等内容红广泛使用。

public enum CommonCodeEnum{

    // '状态信息(1-未审核,2-已审核,3-审核通过, 4-审核作废)',
    STATUS_INFO_1(1, "未审核"),
    STATUS_INFO_2(2, "已审核"),
    STATUS_INFO_3(3, "审核通过"),
    STATUS_INFO_4(4, "审核作废");

    private int code;
    private String caption;
    ComnCodeEnum(int code, String caption) {
        this.code = code;
        this.caption = caption;
    }
    
    public int code() {
        return code;
    }
    public String caption(){
        return caption;
    }
}
复制代码

定义了枚举类信息后,我们便可以在代码中使用枚举值来代替魔法值

if(CommonCodeEnum.STATUS_INFO_1.code().equals(user.getStatus())){
    ...
}else{
    ...
}
复制代码

2.3 消除魔法值的必要性

在使用静态常量或枚举类来替代代码中的魔法值时,我们发现大多数地方的代码并没有简化,反而更加复杂了,而我们原来的使用方式也没有不妥,因此会引发一种思考:大量重复使用的常量抽取定义是应该的,但是仅在类中使用一次或在方法中局部使用的字符串和数值,定义静态常量或枚举类是否有必要呢?

  • 这个问题可以说见仁见智了,代码的规范对于参与人数较多、模块精细化的大项目是十分有必要的,因为每个人都有自己的开发风格,将不同的个人风格杂揉到一个项目中,产生的那叫四不像。
  • 当然,对于个人开发的小项目,只要保证业务逻辑数据的正确性,对于开发规范也没那么重要,但是不得不说遵循规范的开发在后期维护时那叫一个流畅!

3. 总结

在工作中学习,不断提升自己,通过解决代码中魔法值规范提醒的问题,发现:

  • 开发中要不断提升自己的代码规范意识,项目中一大半的bug都是由于代码不规范造成的
  • 善用各种代码规范工具,如阿里巴巴Java开发规范插件,代码质量扫描工具等,发现并解决问题、学习积累知识

猜你喜欢

转载自juejin.im/post/7016704451859709965