文章目录

  • 1 场景
  • 2 步骤
    • 2.1 直接使用
      • 2.1.1 优点
      • 2.1.2 缺点
    • 2.2 静态常量
      • 2.2.1 优点
      • 2.2.2 缺点
    • 2.3 枚举
      • 2.3.1 优点
      • 2.3.2 缺点
    • 2.4 枚举+命名空间
      • 2.4.1 枚举基础接口
      • 2.4.2 枚举实现类
      • 2.4.3 枚举命名空间
      • 2.4.3 使用

1 场景

本文主要讲下java程序中对于状态数据状态代码状态名称如何管理的问题。

对于数据的状态,程序中,经常不会存储状态的名称,而会存储状态对应的代码

每个java后端开发,面对数据库中的一个字段注释:

del_flag  删除状态(0:正常;1:删除;)

都会纠结一个问题,在java代码中,这个字段delFlag对应的01和分别对应的含义正常删除,写在java代码的哪个地方比较合适?

很多人认为这个对于很大的项目来说无非是个很小的事,写在哪里,无所谓,都不会影响我们的项目。讲道理,这个无法反驳。

这篇文章,让我们一起剖析下这件微不足道的小事。

在这里,我们为了方便,定义状态代码状态名称的类型均为字符串

2 步骤

2.1 直接使用

最简单的用法,就是直接在程序中使用状态的代码,如下。

//(1)设置删除标记为正常
record.setDelFlag("0");
......
//(2)判断删除标志
if("0".equals(record.getDelFlag())){return "正常";
}
2.1.1 优点

项目初期管理简单,不用花费时间进行代码封装。

2.1.2 缺点

(1)项目中出现大量手写状态代码状态名称。代码检查工具会提示魔法值,如项目中对代码检查要求高,此部分代码无法合并主干代码。

(2)如果状态代码对应的状态名称发生了变动,全局更改起来,将是十分致命的。

(3)研发人员水平不一致,手动在代码里写状态代码和状态名称,十分容易写错

2.2 静态常量

部分项目,会定义一个java类,将状态码定义为其中的静态常量。其中定义了项目中用到的所有状态代码

public class StateContext{/*** 正常*/public static final String NORMAL="0";/*** 删除*/public static final String DEL="1";//其他状态代码......
}

静态常亮的使用方式如下:

//(1)设置删除标记为正常
record.setDelFlag(StateContext.NORMAL);
......
//(2)判断删除标志
if(StateContext.NORMAL.equals(record.getDelFlag())){return "正常";
}
2.2.1 优点

状态代码,可以直接通过类的静态变量使用(状态名称,也可以通过类的静态变量定义)。

2.2.2 缺点

(1)需要在类中大量定义静态变量,使用时,需十分明确使用的变量的名字,勿使用成别的变量。

(2)一般只通过静态变量定义状态代码状态名称也可这么定义。使用时,对应关系容易对应不上。

2.3 枚举

每种状态信息,定义专门的枚举类。

/*** 删除标志枚举*/
public enum DelFlagEnum{NORMAL("0","正常"),DEL("1","删除");private DelFlagEnum(String code,String name){this.code=code;this.name=name;}/*** 代码*/private String code;/*** 名称*/private String name;public String getCode() {return code;}public String getName() {return name;}}
2.3.1 优点

(1)每种状态定义一个专门的枚举类,枚举类中的定义十分明确

(2)可通过枚举属性准确对应的状态代码和状态名称。

(3)定义的枚举是有属性的,可以在枚举中定义专门的特殊方法,应对特殊的业务。

2.3.2 缺点

枚举主动在代码中使用,是没有问题的。如下:

DelFlagEnum.NORMAL.getCode();

但是状态代码一般都会存储在数据库中,如果通过数据库中获取的状态代码获取枚举对象,基础的枚举信息,无法实现此功能。

故可以在枚举中,定义专门的方法,通过状态代码获取枚举或通过状态名称获取枚举。如下

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;/*** 删除标志枚举*/
public enum DelFlagEnum{NORMAL("0","正常"),DEL("1","删除");private DelFlagEnum(String code,String name){this.code=code;this.name=name;}/*** 枚举集合*/private static final List<DelFlagEnum> ENUM_LIST= EnumUtils.getEnumList(DelFlagEnum.class);/*** 通过代码获取枚举* @param code 枚举代码* @return 枚举*/public static DelFlagEnum getEnumByCode(String code){if(StringUtils.isNotEmpty(code) && CollectionUtils.isNotEmpty(ENUM_LIST)){for(DelFlagEnum delFlagEnum:ENUM_LIST){if(code.equals(delFlagEnum.getCode())){return delFlagEnum;}}}return null;}/*** 通过名称获取枚举* @param name 枚举名称* @return 枚举*/public static DelFlagEnum getEnumByName(String name){if(StringUtils.isNotEmpty(name) && CollectionUtils.isNotEmpty(ENUM_LIST)){for(DelFlagEnum delFlagEnum:ENUM_LIST){if(name.equals(delFlagEnum.getName())){return delFlagEnum;}}}return null;}/*** 代码*/private String code;/*** 名称*/private String name;public String getCode() {return code;}public String getName() {return name;}
}

但是,如果每个枚举都是这样写。代码量大大增加,极易出现拷贝导致的低级错误。因此需对此代码进行封装,减少开发人员的工作量。

2.4 枚举+命名空间

此种方式,是对2.3中枚举定义状态值进行了代码封装

这是作者当前找到的最优的方式,建议使用。

2.4.1 枚举基础接口

定义基础枚举接口。接口中定义枚举中必有的两个方法(获取代码、获取名称)

public interface BaseEnum {/*** 获取代码* @return*/String getCode();/*** 获取名称* @return*/String getName();
}
2.4.2 枚举实现类

每种状态对应专门的枚举类,每个枚举类均需实现接口BaseEnum(javac编译器,枚举无法继承,所以成员变量、接口方法,还需要手动写)。

枚举类中仍然可以定义专门的方法,来执行特殊业务。

public enum DelFlagEnum implements BaseEnum{NORMAL("0","正常"),DEL("1","删除");/*** 代码*/private String code;/*** 名称*/private String name;private DelFlagEnum(String code, String name){this.code=code;this.name=name;}@Overridepublic String getCode() {return this.code;}@Overridepublic String getName() {return this.name;}
}
2.4.3 枚举命名空间

可以通过此命名空间实现如下功能:

(1)通过代码获取枚举(时间复杂度O(1))

(2)通过名称获取枚举(时间复杂度O(n))

上述两个方法均线程安全,且均为懒加载,即用到方法时才去初始化对应的枚举类缓存。

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 枚举命名空间*/
public class EnumContext {/*** 枚举集合映射*/private static final Map<String, Map<String, BaseEnum>> ENUM_MAP = new ConcurrentHashMap<>();/*** 初始化枚举map*/private synchronized static <T extends BaseEnum> void initEnumMap(Class<T> enumClass) {if (enumClass != null && enumClass.isEnum()) {String key = enumClass.getName();if (!ENUM_MAP.containsKey(key)) {Map<String, BaseEnum> map = new ConcurrentHashMap<>();BaseEnum[] baseEnums = enumClass.getEnumConstants();if (baseEnums != null && baseEnums.length > 0) {for (final BaseEnum e : baseEnums) {map.put(e.getCode(), e);}}ENUM_MAP.put(key, map);}}}/*** 通过代码获取枚举(时间复杂度O(1))** @param code      代码* @param enumClass 枚举类* @return 枚举*/public static <T extends BaseEnum> T getEnumByCode(String code, Class<T> enumClass) {if (StringUtils.isNotEmpty(code) && enumClass != null) {String key = enumClass.getName();if (!ENUM_MAP.containsKey(key)) {//如果不存在=>初始化initEnumMap(enumClass);}//如果已存在=>判断Map<String, BaseEnum> map = ENUM_MAP.get(key);if (MapUtils.isNotEmpty(map)) {return (T) map.get(code);}}return null;}/*** 通过名称获取枚举(时间复杂度O(n))** @param name      代码* @param enumClass 枚举类* @return 代码*/public static <T extends BaseEnum> T getEnumCodeByName(String name, Class<T> enumClass) {if (StringUtils.isNotEmpty(name) && enumClass != null) {String key = enumClass.getName();if (!ENUM_MAP.containsKey(key)) {//如果不存在=>初始化initEnumMap(enumClass);}//如果已存在=>判断Map<String, BaseEnum> map = ENUM_MAP.get(key);if (MapUtils.isNotEmpty(map)) {for (Map.Entry<String, BaseEnum> entry : map.entrySet()) {if (entry.getValue() != null && name.equals(entry.getValue().getName())) {return (T) entry.getValue();}}}}return null;}
}
2.4.3 使用
//直接使用枚举
System.out.println(DelFlagEnum.NORMAL.getCode() + "  " + DelFlagEnum.NORMAL.getCode());//通过代码获取枚举
DelFlagEnum normalEnum = EnumContext.getEnumByCode("0", DelFlagEnum.class);
if (normalEnum != null) {System.out.println(normalEnum.getCode() + "  " + normalEnum.getName());
}//通过名称获取枚举
DelFlagEnum delEnum = EnumContext.getEnumCodeByName("删除", DelFlagEnum.class);
if (delEnum != null) {System.out.println(delEnum.getCode() + "  " + delEnum.getName());
}

java中枚举表示数据状态相关推荐

  1. Java 中的面向数据编程

    近年来, Amber项目为 Java 带来了许多新特性-- 局部变量类型推断. 文本块. 记录类. 封印类. 模式匹配 等等.虽然这些特性都是独立的,但也可以组合在一起使用.具体地说,记录类.封印类和 ...

  2. java培训教程分享:Java中怎样将数据对象序列化和反序列化?

    本期为大家介绍的java培训教程是关于"Java中怎样将数据对象序列化和反序列化?"的内容,相信大家都知道,程序在运行过程中,可能需要将一些数据永久地保存到磁盘上,而数据在Java ...

  3. java中map转为json数据_Java技术-将java中Map类型数据转化为json数据并以Ajax形式返回...

    Java技术-将java中Map类型数据转化为json数据并以Ajax形式返回html 1.自定义工具类(简单易用)-下面是我写的一个简单的工具类前端 package com.test.util; i ...

  4. Java中枚举的线程安全性及序列化问题

    转载自  Java中枚举的线程安全性及序列化问题 Java SE5提供了一种新的类型-Java的枚举类型,关键字enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序 ...

  5. java基础----Java中枚举的使用(一)

    这里介绍一下java中关于枚举的使用. java中枚举的使用 一.枚举中可以定义方法 参照于TimeUnit的使用,TimeUnit.MILLISECONDS.sleep(1000); LoveUti ...

  6. Java中判断当前数据是否全为数字

    Java中判断当前数据是否全为数字 总共又三种方法 一.用JAVA自带的函数编写判断机制 二.用正则表达式编写判断机制 三.用ascii码编写判断机制 总共又三种方法 一.用JAVA自带的函数编写判断 ...

  7. Java中使用JSON数据传递

    一.Java中使用JSON数据传递 pom依赖引入 <dependency><groupId>com.alibaba</groupId><artifactId ...

  8. 操作系统中进程的五种状态与JAVA中线程的六种状态

    操作系统中的五种状态 新建:创建新的进程 就绪:进程已经获得除CPU时间片以外的任何资源,一旦获得cpu时间片就能立马执行. 执行:处于就绪队列中的进程获得了时间片运行进程. 阻塞:进程时间片用完进入 ...

  9. 19、java中枚举

    枚举是什么? 枚举就是将一个有限集合中的所有元素列举出来,在java中使用可以使用enum关键字来声明一个枚举类. 为什么使用枚举? 之前当用到一些常量时,便临时声明一个,这样使得代码看起来很乱,这里 ...

最新文章

  1. 关于oracle的基础增删改查操作总结
  2. 广播代码_代码广播:专为编码而设计的24/7音乐
  3. Linux Kernel 3.0新特性概览(转)
  4. 霍尔电流传感器ACS712的性能参数和用法
  5. Windows 10企业批量部署实战之刷新并添加启动映像
  6. javaWeb项目带红色感叹号问题原因
  7. android 监听 h5 window,H5嵌入APP后,通过window.WebViewJavascriptBridge原生APP与H5之间交互...
  8. CetnOS 6.7安装Hive 1.2.1
  9. ZOJ Problem Set - 1292 Integer Inquiry
  10. 计算机二级c语言必看,计算机二级C语言考试必看技巧
  11. win10c语言关机,win10电脑自动关机命令
  12. 高通芯片资料下载大全,这是一个资料下载论坛
  13. 正式“退休”的Flash,未来我们会怀念它吗?
  14. 5G移动通信网络构架与关键技术要点探讨
  15. 计算机第十三套试题,2012年计算机二级VB第十三套上机试题及解析
  16. 邮箱客户端程序的实现
  17. 全屏背景图移动端滚动时白底问题
  18. Vue中图片加载问题总结
  19. Ubuntu / Python / Mega自动同步监控照片
  20. 【算法基础四】C语言小项目实战---通讯录管理系统(单链表)

热门文章

  1. 2021年8月上中旬好文收藏(1)
  2. 为什么系统调用会消耗较多资源?系统调用的三种方法:软件中断(分析过程)、SYSCALL指令、vDSO(虚拟动态链接对象linux-vdso.so.1)
  3. srsLTE源码学习:RLC,无线链路控制子层抓包rlc_pcap.h,rlc_pcap.cc
  4. 排序算法:归并排序(C、Java)
  5. java的值排序总结
  6. java 线程锁概念_Java多线程——锁概念与锁优化
  7. oracle adg 人工干预,Oracle DataGuard
  8. Cron表达式的正则表达式
  9. 微信开源推理加速工具 TurboTransformers,性能超越 PyTorch/TensorFlow 与主流优化引擎
  10. OpenJS 基金会推出 Node.js 证书,JS 开发者可以“考证”了