Java枚举中定义属性

news2024/11/24 15:01:34

文章目录

  • 1、复习枚举
  • 2、自定义属性
  • 3、自定义属性枚举类和常量的对比
  • 4、常用方法
  • 5、枚举自定义属性在开发中的应用:字典表
  • 6、补充:入参校验

刚接触枚举时的例子太简单,就一个Season枚举类,里面四个常量值,后来开发中看到枚举中定义属性就很看不惯。这里梳理下Java枚举中定义属性,以及枚举在开发中的实际应用举例。

1、复习枚举

  • Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一年的 12 个月份
  • Java枚举类使用enum定义,各个常量之间用逗号分隔
enum Color 
{ 
    RED, GREEN, BLUE; 
} 
  • 枚举类中引用每一个常量值,用类名.常量
public class Test
{
    public static void main(String[] args)
    {
        Color c1 = Color.RED;
        System.out.println(c1);
    }
}

//输出RED
  • 初学时的经典例子,和switch连用
public class MyClass {
  public static void main(String[] args) {
    Color myVar = Color.BLUE;

    switch(myVar) {
      case RED:
        System.out.println("红色");
        break;
      case GREEN:
         System.out.println("绿色");
        break;
      case BLUE:
        System.out.println("蓝色");
        break;
    }
  }
}
//蓝色
  • 内部类中使用枚举
public Class MyDemo{

	 enum Color
	    {
	        RED, GREEN, BLUE;
	    }
	    
	public void doSome(){
       ....
	}
 
}

2、自定义属性

枚举类的语法结构虽然和普通类不一样,但是经过编译器之后产生的也是一个class文件。该class文件再反编译回来可以看到实际上是生成了一个类。该类继承了java.lang.Enum<E>,且所有的枚举值都是 public static final 的,以上枚举类Color可理解为:

//java为单继承,因此不能再继承其他类
class Color extends java.lang.Enum
{
     public static final Color RED = new Color();
     //枚举中的常量,可以看作是一个个对象,看到这儿应该get到枚举中定义属性的操作了
     public static final Color BLUE = new Color();
     public static final Color GREEN = new Color();
}

看到上面的反编译代码,对枚举中定义成员变量,枚举值有属性值的操作应该捋顺了!举个定义属性的简单例子:

public enum Domain {
 
 
    XB("11","西北"),
    HD("13","华东"),
    DB("14","东北"),
    HB("15","华北");
 
    private String code;
    private String name;
 
    Domain(String code,String name) {
        this.code = code;
        this.name = name;
    }
 
    public String getCode() {
        return code;
    }
    public String getName(){
        return name;
    }
}

3、自定义属性枚举类和常量的对比

上面提到所有的枚举值都是 public static final 的,可能会有疑问:那直接用常量不得了?

===>

自定义属性枚举是常量的升级版,二者有各自的应用场景。当就只需要一个静态变量名 = 值 时,直接用常量自然最快,如:

在这里插入图片描述

但当你的一个值背后需要连着多个信息时,就只能用枚举+自定义属性来表达!

4、常用方法

enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。

枚举类中常用的三个方法:values()、ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:

  • values() 返回枚举类中所有的值
  • ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样
  • valueOf()方法返回指定字符串值的枚举常量
enum Color
{
    RED, GREEN, BLUE;
}
 
public class Test
{
    public static void main(String[] args)
    {
        // 调用 values()
        Color[] arr = Color.values();
 
        // 迭代枚举
        for (Color col : arr)
        {
            // 查看索引
            System.out.println(col + " at index " + col.ordinal());
        }
 
        // 使用 valueOf() 返回枚举常量,不存在的会报错 IllegalArgumentException
        System.out.println(Color.valueOf("RED"));
        // System.out.println(Color.valueOf("WHITE"));
    }
}

运行结果:

RED at index 0
GREEN at index 1
BLUE at index 2
RED

5、枚举自定义属性在开发中的应用:字典表

看一个例子,有一个审核流的需求,审核状态只有四种,定义字典表:

在这里插入图片描述

为了后面写代码方便和规范,定义下面这个枚举类

import brave.internal.Nullable;

import java.util.HashMap;
import java.util.Map;

public enum AuditStatusEnum {
    BEFORE("before","待提交"),
    WAIT("wait", "待审核"),
    NO("no", "审核未通过"),
    PASS("pass","审核通过");

    String code;
    String name;

    AuditStatusEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }

    private static final Map<String, AuditStatusEnum> mappings = new HashMap<>(5);

    static {
        for (AuditStatusEnum statusEnum : values()) {
            mappings.put(statusEnum.code, statusEnum);
        }
    }

    public String getCode(){
        return code;
    }

    public String getName(){
        return name;
    }

    @Nullable
    public static AuditStatusEnum resolve(@Nullable String code) {
        return (code != null ? mappings.get(code) : null);
    }
}

分析:

  • 两个属性,一个为code,一个为中文名,常见操作
  • values()方法获取枚举成员的所有值,返回一个数组
  • 写静态代码块,遍历上面的数组,以枚举值的code为键,以枚举值本身为值,放进Map集合
  • 静态方法resolve()则是根据枚举值的code查询枚举值
  • 定义静态方法resolve,妙在利用了Java类加载的时机之一 : 访问静态方法 。访问静态方法 ==> 类加载 ==> 静态代码块执行 ⇒ 枚举值被全存到Map中,方便后面查询
/定义了上面的字典对应的枚举类后,写业务逻辑代码:


if (xxDto.getAuditCode().equals(AuditStatusEnum.NO.getCode())){
	return new MyException("审核未通过,不可操作!");
}





在这里插入图片描述

6、补充:入参校验

最后,工作时看到同事写的这个入参校验也蛮有意思,记录一下:


有个需求,它的某个接口有个传参,如排序字段orderField,该字段的可取值固定,只有create_time和name,为了防止非法传参,需要对这个入参做校验,此时也可用自定义属性的枚举类实现。

//当然想实现这个校验,直接把字段塞进集合,判断传参的值在不在集合中也能实现
//但这样一来后期扩展不方便,二来则是每个公司的代码规范要求

接下来演示枚举类:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

@Getter
@AllArgsConstructor
public enum OrderFieldEnum {
    CREATE_TIME("createTime", "create_time"),
    NAME("name","name");
    
    private final String value;  //值
    private final String field;  //对应数据库中的字段,方便后面写业务和Mapper层代码
    
    private static final Map<String, OrderFieldEnum> map = new HashMap<>();
    

    @JsonCreator
    public static OrderFieldEnum check(String value) {
    	//这里的判断map为空则遍历枚举类的值放进Map中
    	//这个操作和上面的利用类加载时机初始化Map集合一个目的
        if (map.isEmpty()) {
            for (OrderFieldEnum orderFieldEnum : OrderFieldEnum.values()) {
                map.put(orderFieldEnum.getValue(), orderFieldEnum);
            }
        }
        //如果在Map中找不到对应的key和传入的字段相等,则认为非法传参,即不支持这个排序字段
        if (!map.containsKey(value)) {
     
            throw new MyExceptionHandler("不支持这个排序字段");  //自定义异常,在全局异常处理器处理
        }
        //否则返回整个枚举对象
        return map.get(value);
    }

    @JsonValue
    public String getValue() {
        return value;
    }
}

此时,校验入参可:

OrderFieldEnum.check(dto.getOrderField().getValue());

记录下他的另一种校验的实现方式,虽然写多了,但通用性更强

checkParamRegion(dto.getOrderField(), List.of(OrderFieldEnum.CREATE_TIME, OrderFieldEnum.NAME));

public void checkParamRegion(Object param, Collection<?> regions) {
		//判断Object param是集合类型还是非集合
        if (param instanceof List) {
            List list = (List) param;
            for (Object o : list) {
                if (!regions.contains(o)) {
	                throw new MyExceptionHandler("参数超过了给定范围");
                }
            }
        } else {
            if (!regions.contains(param)) {
                throw new MyExceptionHandler("参数超过了给定范围");
            }
        }
    }

最后,写mapper层的排序,拿排序字段可:

OrderFieldEnum.CREATE_TIME.getField()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/599730.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口幂等方案

文章目录 概要方案乐观锁数据库唯一索引令牌tokentoken通过另一个接口从服务端获取客户端自身生成token 总结 概要 所谓接口幂等性&#xff0c;就是一次和多次请求某一个资源对于资源本身应该具有同样的影响。接口幂等的应用很广&#xff0c;小到防止表单重复提交&#xff0c;…

使用kettle完成学生成绩登记需求

&#xff08;一&#xff09; 使用kettle完成学生成绩登记需求 学生成绩表下表所示。(自己创建一个学生表) 在MySQL中创建一个名为school的数据库&#xff0c;并在school数据库中创建一个名为score的表&#xff0c;使用Kettle将Excel形式的学生成绩表导入MySQL的score表 1&am…

机器视觉海康工业相机SDK参数设置获取

视觉人机器视觉培训-缺陷检测项目-食品行业草鸡蛋外观检测 相机参数类型可分为六类,除 command 参数外,每一类都有其对应的设置与获取函数接口。 表 1 参数类型及对应函数接口介绍 *详细函数接口可参考 SDK 手册: ​C:\Program Files (x86)\MVS\Development\Documentation…

【已解决】微信小程序报错:request 合法域名校验出错 如若已在管理后台更新域名配置,请刷新项目配置后重新编译项目,操作路径:“详情-域名信息”

【已解决】微信小程序报错&#xff1a;request 合法域名校验出错 如若已在管理后台更新域名配置&#xff0c;请刷新项目配置后重新编译项目&#xff0c;操作路径&#xff1a;“详情-域名信息” 场景复现解决方法 知识专栏专栏链接微信小程序专栏https://blog.csdn.net/xsl_hr/c…

工控设备如何防勒索病毒

目前现状 无论是中小企业还是大型企事业单位&#xff0c;均有属于自己的内网或公有云服务器。这些服务器有的是专门的SVN、GIT代码服务器&#xff0c;有的是文档存储服务器&#xff0c;有的是应用服务器。服务器是企业的核心命脉&#xff0c;所有知识产权及多年心血都集中汇总…

LeetCode——Pow(x, n)

一、题目 50. Pow(x, n) - 力扣&#xff08;Leetcode&#xff09; 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数&#xff08;即&#xff0c;xⁿ &#xff09;。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000示例 2&#x…

Jetpack Compose中的状态栏适配(Window Insets)

除了app的内容区域外&#xff0c;还有一些其他的固定元素会显示在手机屏幕上&#xff0c;顶部的状态栏、 刘海、 底部的导航栏&#xff0c;还有输入法键盘&#xff0c;它们都是系统的UI&#xff0c; 也叫Insets. 如图所示: 顶部的状态栏通常被用来展示通知, 设备状态等; 底部导…

软考A计划-网络规划设计师-学习笔记-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

Linux 如何判断文件的类型

在Linux中&#xff0c;我们如何判断一个文件的类型和用户权限呢&#xff1f; 在c语言中&#xff0c;Linux为我们提供了一个结构体stat我们可以通过 #include<sys/stat.h>引入后使用。然后通过stat中的st_mode来判断文件的类型。如下图&#xff0c;我们要知道文件是什么类…

超级入门:R 语言的 5 种基本数据类型

一、R语言简介 R语言是一种用于统计计算和绘图的编程语言&#xff0c;它是由新西兰奥克兰大学的 Ross Ihaka 和 Robert Gentleman 开发的。R语言支持向量和矩阵计算&#xff0c;因此也可以用于数值分析和线性代数。它主要应用于数据分析、统计学习、数据挖掘、数据可视化等领域…

【Springboot】集成QQ邮箱信息发送

系列文章目录 文章目录 系列文章目录前言添加Maven依赖QQ邮箱开启POP服务配置application.properties文件Controller层编写 vue前端&#xff08;也可以直接省略&#xff09; 前言 这篇博客用于简单实现SpringBoot中发送请求&#xff0c;用户可以收到邮件。 添加Maven依赖 <…

ISIS 实验

(1)拓扑图 2&#xff09;需求&#xff1a; -实现PC1和PC2的通信 3&#xff09;配置步骤&#xff1a; -配置接口IP地址 -开启ISIS---类似于在OSPF中创建进程 -配置NET地址---类似于在OSPF中创建区域&#xff0c;指定Router-id -在接口上启用ISIS--类似于在OSPFv2中用ne…

SKNet讲解

SKNet讲解 0. 引言1. 网络结构1.1 Split部分1.2 Fuse部分1.3 Select部分1.4 三分支的情况 2. SKNet网络体系结构3. 分析与解释4. 代码总结 0. 引言 视皮层神经元的感受野大小受刺激的调节&#xff0c;即对不同刺激&#xff0c;卷积核的大小应该不同&#xff0c;但在构建CNN时一…

<DB2>《DB2创建分区表及相关操作》(精华)

《DB2创建分区表及相关操作》 1 基本概念2 操作2.1 查看数据库中存在的分区表2.2 查看分区表详细2.3 断开对数据表的访问连接2.4 备份数据2.5 拆离分区2.6 添加分区2.7 导入数据2.8 校验前后数据2.9 删除临时表数据 1 基本概念 当表中的数据量不断增大&#xff0c;查询数据的速…

使用Kettle实现数据排序

一、Kettle的安装 1.下载Kettle的安装包文件 在Windows系统中打开浏览器&#xff0c;访问Kettle官网&#xff08;https://sourceforge.net/projects/pentaho/&#xff09;&#xff0c;下载Kettle安装文件pdi-ce-9.1.0.0-324.zip。 或者在我的百度网盘分享里面下载 链接&…

【软件测试】软件测试总结笔记(2)

软件测试过程&#xff08;内容&#xff09; 1.单元测试基本概念定义⭐单元测试环境⭐单元测试内容单元测试用例的设计思路⭐单元测试的过程 2. 集成测试集成测试内容集成测试优点⭐集成测试层次集成测试方法Drivers and Stubs ⭐集成策略&#xff08;基于分解的集成&#xff09…

crontab定时任务介绍

1 crontab概述 crontab是linux操作系统上用来设置定时任务的基础命令&#xff0c;是基于crond服务实现任务调度执行。 当安装完成操作系统后&#xff0c;默认会安装crond服务及其附属命令&#xff0c;并且会自动启动crond进程&#xff0c;crond进程每分钟会定期检查是否有要执…

Python量化交易:策略创建运行流程

学习目标 目标 知道策略的创建和运行知道策略的相关设置知道RQ的策略运行流程应用 无 1、体验创建策略、运行策略流程 1.1 创建策略 1.2 策略界面 2、 策略界面功能、运行介绍 2.1 一个完整的策略需要做的事情 选择策略的运行信息&#xff1a; 选择运行区间和初始资金选择回…

水库大坝安全问题有哪些?

我国现有水库大坝9.8万余座&#xff0c;80%水库大坝修建于上世纪50至70年代&#xff0c;受经济、技术等历史因素的影响&#xff0c;存在坝体结构破损、坝基渗漏、坝体渗漏、坝面变形等严重的安全隐患。 一、水库大坝的安全问题主要包括以下几个方面&#xff1a; 1.坝体结构破损…

“微商城”项目(3页面布局)

1.设置标题 设置页面头部标题&#xff0c;方便告诉用户当前显示的是哪一个页面。编辑src\router.js文件&#xff0c;示例代码如下。 routes: [{ path: /, redirect: /home, meta: { title: 首页 } },{ path: /home, component: Home, name: home, meta: { title: 首页 } } ] …