Java知识点整理 17 — 消灭魔法值

一. 什么是魔法值

魔法值通常是指在编写代码时凭空出现的数字或字符串,如果没有注释,无法直接判断其代表的含义,必须通过分析代码上下文才能明白。

魔法值会严重降低代码可读性与可维护性。在一个周期相对较长的项目中,很可能后续在回顾之前编写的代码时忘记这类魔法值代表的含义,如果没有注释或批注,将严重影响开发进度。个人项目亦是如此,更何况别人的项目代码。

例如:

gender.setGender(0); // 设置性别为女
gender.setGender(1); // 设置性别为男

statu.setStatus(0); //表示状态正常
statu.setStatus(1); //表示状态异常

……

阿里巴巴 Java 开发规范手册中明确指出:不允许任何魔法值(即未经定义的常量)直接出现在代码中。

二. 魔法值替换

1. 常量

使用 public static final 修饰的成员变量,必须有初始化值,且一旦被初始化,执行过程中值将不可变。通常使用英文单词全部大写,多个单词之间使用下划线连接。

// 标识用户性别
public class UserGender {
   // 0 代表女性
   public static final Integer USER_GENDER_FEMALE = 0;
   // 1 代表男性
   public static final Integer USER_GENDER_MALE = 1;

}

// 标识用户状态常量
public class UserStatus {
    // 0 代表正常 
    public static final Integer USER_NORMAL  = 0;
    // 1 代表异常
    public static final Integer USER_ABNORMAL  = 1;
    // 2 代表禁止
    public static final Integer USER_PROHIBIT  = 2;
}

在使用常量时,Java 会在编译阶段自动进行替换,将常量替换成真实的字面量。

// 使用常量 UserGender.USER_GENDER_MALE
System.out.println(UserGender.USER_GENDER_MALE);
// java会在编译阶段替换为字面量 1
System.out.println(1);

在业务中具体使用时可以显著提高代码可读性,如果想要修改值,在 UserGender 类中修改即可,所有引用处都会生效。

// 使用魔法值
user.setGender(0);

// 使用常量
user.setGender(UserGender.USER_GENDER_FEMALE);

2. 枚举类

通过枚举类,开发者可以固定要接收的常量数值,适合需要约束接收值的场景。

对于相对简单的场景,直接使用枚举示例:

// 协议状态枚举
public enum ProtocolMessageStatusEnum {
 
    OK, // 请求成功
    BAD_REQUEST, // 请求失败
    BAD_RESPONSE; // 响应失败

}

使用时直接调用,但只能获取事先罗列的枚举类实例:

public class Test {
   public static void main(String[] args) {
      System.out.println(ProtocolMessageStatusEnum.OK);
      System.out.println(ProtocolMessageStatusEnum.BAD_REQUEST);
      System.out.println(ProtocolMessageStatusEnum.BAD_RESPONSE);
   }
}

在相对复杂的场景中,可以给每个实例增加一个或多个值。

例如在 RPC 项目实现自定义协议部分,曾创建响应状态的枚举类:

import lombok.Getter;
 
/**
 * 协议消息的状态枚举
 */
@Getter
public enum ProtocolMessageStatusEnum {
 
    OK("ok", 20),
    BAD_REQUEST("badRequest", 40),
    BAD_RESPONSE("badResponse", 50);
 
    // 可以有多个字段
    private final String text;
 
    private final int value;
 
    // 必须提供对应参数构造器
    ProtocolMessageStatusEnum(String text, int value){
        this.text = text;
        this.value = value;
    }
 
    /**
     * 根据 value 获取枚举
     *
     * @param value
     * @return
     */
    // 开放获取实例值权限
    public static ProtocolMessageStatusEnum getEnumByValue(int value){
        for (ProtocolMessageStatusEnum anEnum : ProtocolMessageStatusEnum.values()){
            if (anEnum.value == value){
                return anEnum;
            }
        }
        return null;
    }
}

在使用时可以直接调用,并且多了自定义方法,getEnumByValue:

header.setStatus((byte) ProtocolMessageStatusEnum.OK.getValue());

……

eader.setSerializer((byte) ProtocolMessageSerializerEnum.getEnumByValue( …… );

当我们将枚举类应用在方法参数列表中,那就有很强的约束性。此外,如果对于一些方法只能接受数值,还可以通过 values 获取所有值,然后判断数值的正确性。

public class App {
    public static void main(String[] args) {
        setStatus(UserStatusEnum.NORMAL);
    }

    public static void setStatus(UserStatusEnum userStatus){
        // 判断参数是否为对于枚举实例
        if(isTrueValue(status)){
           User user = new User();
           user.setStatus(status);
        } else {
           Syetem.out.println("非法参数");
    }

    // 判断参数是否为对于枚举实例
    public static boolean isTrueValue(Integer num) {
        UserStatusEnum[] values = UserStatusEnum.values();
        for (UserStatusEnum statusEnum : values) {
            Integer value = statusEnum.getValue();
            if (value.equals(num)) {
                return true;
            }
        }
        return false;
    }
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Phoenixxxxxxxxxxxxx

感谢支持!

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

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

打赏作者

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

抵扣说明:

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

余额充值