看看人家在接口中使用枚举类型的方式,那叫一个优雅!

声明式查询服务,只需定义,无需实现 ValidatedOrderDetail getById(@Valid @NotNull(message = "订单号不能为null") Long id);Page pageByUserId(@Valid @NotNull(message = "查询参数不能为 null") PageByUserId query); 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:geekhalo

b805e60552e719fe88f6cb7bdae6478f.jpeg


1. 概览

枚举作为 Java 5 的重要特征,相信大家并不陌生,但在实际开发过程中,当 name 和 ordrial 发生变化时,如果处理不当非常容易引起系统bug。这种兼容性bug非常难以定位,需要从框架层次进行避免,而非仅靠开发人员的主观意识。

1.1. 背景

枚举很好用,特别是提供的 name 和 ordrial 特性,但这点对重构造成了一定影响,比如:

  1. 某个枚举值业务语义发生变化,需要将其进行 rename 操作,以更好的表达新业务语义

  2. 新增、删除或者为了展示调整了枚举定义顺序

这些在业务开发中非常常见,使用 IDE 的 refactor 功能可以快速且准确的完成重构工作。但,如果系统将这些暴露出去或者存储到数据库等存储引擎就变得非常麻烦,不管是 name 还是 ordrial 的变更都会产生兼容性问题。

对此,最常见的解决方案便是放弃使用 name 和 ordrial,转而使用控制能力更强的 code。

1.2. 目标

提供一组工具,以方便的基于 code 使用枚举,快速完成对现有框架的集成:

  1. 完成与 Spring MVC 的集成,基于 code 使用枚举;加强返回值,以对象的方式进行返回,信息包括 code、name、description

  2. 提供统一的枚举字典,自动扫描系统中的枚举并将其以 restful 的方式暴露给前端

  3. 使用 code 进行数据存储操作,避免重构的影响

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

2. 快速入门

2.1. 添加 starter

在 Spring boot 项目的 pom 中增加如下依赖:

<groupId>com.geekhalo.lego</groupId>
<artifactId>lego-starter</artifactId>
<version>0.1.19-enum-SNAPSHOT</version>

2.2. 统一枚举结构

如何统一枚举行为呢?公共父类肯定是不行的,但可以为其提供一个接口,在接口中完成行为的定义。

2.2.1. 定义枚举接口

除了在枚举中自定义 code 外,通常还会为其提供描述信息,构建接口如下:

public interface CodeBasedEnum {
    int getCode();
}
public interface SelfDescribedEnum {
    default String getName(){
        return name();
    }

    String name();

    String getDescription();
}
public interface CommonEnum extends CodeBasedEnum, SelfDescribedEnum{

}

整体结构如下:

cf4922d2ad6762d74c9ea1f09610f2c0.png

在定义枚举时便可以直接使用CommonEnum这个接口。

2.2.2. 实现枚举接口

有了统一的枚举接口,在定义枚举时便可以直接实现接口,从而完成对枚举的约束。

public enum NewsStatus implements CommonEnum {
    DELETE(1, "删除"),
    ONLINE(10, "上线"),
    OFFLINE(20, "下线");
    private final int code;
    private final String desc;

    NewsStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    @Override
    public int getCode() {
        return this.code;
    }

    @Override
    public String getDescription() {
        return this.desc;
    }
}

2.3. 自动注册 CommonEnum

有了统一的 CommonEnum 最大的好处便是可以进行统一管理,对于统一管理,第一件事便是找到并注册所有的 CommonEnum。

031fe68dcc87dc4d1a93934c3d8961c3.png

以上是核心处理流程:

  1. 首先通过 Spring 的 ResourcePatternResolver 根据配置的 basePackage 对classpath进行扫描

  2. 扫描结果以Resource来表示,通过 MetadataReader 读取 Resource 信息,并将其解析为 ClassMetadata

  3. 获得 ClassMetadata 之后,找出实现 CommonEnum 的类

  4. 将 CommonEnum 实现类注册到两个 Map 中进行缓存

备注:此处万万不可直接使用反射技术,反射会触发类的自动加载,将对众多不需要的类进行加载,从而增加 metaspace 的压力。

在需要 CommonEnum 时,只需注入 CommonEnumRegistry Bean 便可以方便的获得 CommonEnum 的具体实现。

2.4. Spring MVC 接入层

Web 层是最常见的接入点,对于 CommonEnum 我们倾向于:

  1. 参数使用 code 来表示,避免 name、ordrial 变化导致业务异常

  2. 丰富返回值,包括枚举的 code、name、description 等

89edffb5ad2ee37d089770b442470e4c.png
2.4.1. 入参转化

Spring MVC 存在两种参数转化扩展:

  1. 对于普通参数,比如 RequestParam 或 PathVariable 直接从 ConditionalGenericConverter 进行扩展

  • 基于 CommonEnumRegistry 提供的 CommonEnum 信息,对 matches 和 getConvertibleTypes方法进行重写

  • 根据目标类型获取所有的 枚举值,并根据 code 和 name 进行转化

  1. 对于 Json 参数,需要对 Json 框架进行扩展(以 Jackson 为例)

  • 遍历 CommonEnumRegistry 提供的所有 CommonEnum,依次进行注册

  • 从 Json 中读取信息,根据 code 和 name 转化为确定的枚举值

两种扩展核心实现见:

@Order(1)
@Component
public class CommonEnumConverter implements ConditionalGenericConverter {
    @Autowired
    private CommonEnumRegistry enumRegistry;

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        Class<?> type = targetType.getType();
        return enumRegistry.getClassDict().containsKey(type);
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return enumRegistry.getClassDict().keySet().stream()
                .map(cls -> new ConvertiblePair(String.class, cls))
                .collect(Collectors.toSet());
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        String value = (String) source;
        List<CommonEnum> commonEnums = this.enumRegistry.getClassDict().get(targetType.getType());
        return commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(value))
                .findFirst()
                .orElse(null);
    }
}

static class CommonEnumJsonDeserializer extends JsonDeserializer{
        private final List<CommonEnum> commonEnums;

        CommonEnumJsonDeserializer(List<CommonEnum> commonEnums) {
            this.commonEnums = commonEnums;
        }

        @Override
        public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
            String value = jsonParser.readValueAs(String.class);
            return commonEnums.stream()
                    .filter(commonEnum -> commonEnum.match(value))
                    .findFirst()
                    .orElse(null);
        }
    }
2.4.2. 增强返回值

默认情况下,对于枚举类型在转换为 Json 时,只会输出 name,其他信息会出现丢失,对于展示非常不友好,对此,需要对 Json 序列化进行能力增强。

首先,需要定义 CommonEnum 对应的返回对象,具体如下:

@Value
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@ApiModel(description = "通用枚举")
public class CommonEnumVO {
    @ApiModelProperty(notes = "Code")
    private final int code;

    @ApiModelProperty(notes = "Name")
    private final String name;

    @ApiModelProperty(notes = "描述")
    private final String desc;

    public static CommonEnumVO from(CommonEnum commonEnum){
        if (commonEnum == null){
            return null;
        }
        return new CommonEnumVO(commonEnum.getCode(), commonEnum.getName(), commonEnum.getDescription());
    }

    public static List<CommonEnumVO> from(List<CommonEnum> commonEnums){
        if (CollectionUtils.isEmpty(commonEnums)){
            return Collections.emptyList();
        }
        return commonEnums.stream()
                .filter(Objects::nonNull)
                .map(CommonEnumVO::from)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}

CommonEnumVO 是一个标准的 POJO,只是增加了 Swagger 相关注解。

CommonEnumJsonSerializer 是自定义序列化的核心,会将 CommonEnum 封装为 CommonEnumVO 并进行写回,具体如下:

static class CommonEnumJsonSerializer extends JsonSerializer{

        @Override
        public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            CommonEnum commonEnum = (CommonEnum) o;
            CommonEnumVO commonEnumVO = CommonEnumVO.from(commonEnum);
            jsonGenerator.writeObject(commonEnumVO);
        }
    }
2.4.3. 效果展示

首先,新建一个测试枚举 NewsStatus,具体如下:

public enum NewsStatus implements CommonEnum {
    DELETE(1, "删除"),
    ONLINE(10, "上线"),
    OFFLINE(20, "下线");
    private final int code;
    private final String desc;

    NewsStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    @Override
    public int getCode() {
        return this.code;
    }

    @Override
    public String getDescription() {
        return this.desc;
    }
}

然后新建 EnumController,具体如下:

@RestController
@RequestMapping("enum")
public class EnumController {
    @GetMapping("paramToEnum")
    public RestResult<CommonEnumVO> paramToEnum(@RequestParam("newsStatus") NewsStatus newsStatus){
        return RestResult.success(CommonEnumVO.from(newsStatus));
    }

    @GetMapping("pathToEnum/{newsStatus}")
    public RestResult<CommonEnumVO> pathToEnum(@PathVariable("newsStatus") NewsStatus newsStatus){
        return RestResult.success(CommonEnumVO.from(newsStatus));
    }

    @PostMapping("jsonToEnum")
    public RestResult<CommonEnumVO> jsonToEnum(@RequestBody NewsStatusRequestBody newsStatusRequestBody){
        return RestResult.success(CommonEnumVO.from(newsStatusRequestBody.getNewsStatus()));
    }

    @GetMapping("bodyToJson")
    public RestResult<NewsStatusResponseBody> bodyToJson(){
        NewsStatusResponseBody newsStatusResponseBody = new NewsStatusResponseBody();
        newsStatusResponseBody.setNewsStatus(Arrays.asList(NewsStatus.values()));
        return RestResult.success(newsStatusResponseBody);
    }

    @Data
    public static class NewsStatusRequestBody {
        private NewsStatus newsStatus;
    }

    @Data
    public static class NewsStatusResponseBody {
        private List<NewsStatus> newsStatus;
    }
}

执行结果如下:

bd2554f2ef58f97bf9f6e80d97377bb1.png

整体符合预期:

  1. 使用 code 作为请求参数可以自动转化为对应的 CommonEnum

  2. 使用 CommonEnum 作为返回值,返回标准的 CommonEnumVO 对象结构

2.5. 通用枚举字典接口

有时可以将 枚举 理解为系统的一类字段,比较典型的就是管理页面的各种下拉框,下拉框中的数据来自于后台服务。

有了 CommonEnum 之后,可以提供统一的一组枚举字典,避免重复开发,同时在新增枚举时也无需进行扩展,系统自动识别并添加到字典中。

2.5.1. 构建字典Controller

在 CommonEnumRegistry 基础之上实现通用字典接口非常简单,只需按规范构建 Controller 即可,具体如下:

@Api(tags = "通用字典接口")
@RestController
@RequestMapping("/enumDict")
@Slf4j
public class EnumDictController {
    @Autowired
    private CommonEnumRegistry commonEnumRegistry;

    @GetMapping("all")
    public RestResult<Map<String, List<CommonEnumVO>>> allEnums(){
        Map<String, List<CommonEnum>> dict = this.commonEnumRegistry.getNameDict();
        Map<String, List<CommonEnumVO>> dictVo = Maps.newHashMapWithExpectedSize(dict.size());
        for (Map.Entry<String, List<CommonEnum>> entry : dict.entrySet()){
            dictVo.put(entry.getKey(), CommonEnumVO.from(entry.getValue()));
        }
        return RestResult.success(dictVo);
    }

    @GetMapping("types")
    public RestResult<List<String>> enumTypes(){
        Map<String, List<CommonEnum>> dict = this.commonEnumRegistry.getNameDict();
        return RestResult.success(Lists.newArrayList(dict.keySet()));
    }

    @GetMapping("/{type}")
    public RestResult<List<CommonEnumVO>> dictByType(@PathVariable("type") String type){
        Map<String, List<CommonEnum>> dict = this.commonEnumRegistry.getNameDict();
        List<CommonEnum> commonEnums = dict.get(type);

        return RestResult.success(CommonEnumVO.from(commonEnums));
    }
}

该 Controller 提供如下能力:

  1. 获取全部字典,一次性获取系统中所有的 CommonEnum

  2. 获取所有字典类型,仅获取字典类型,通常用于测试

  3. 获取指定字典类型的全部信息,比如上述所说的填充下拉框

2.5.2. 效果展示

获取全部字典:

f6ca4fed07e79add6a0c56ed5ebda783.png

获取所有字典类型:

c154f2e548cda651914ccfe499c50808.png

获取指定字段类型的全部信息:

3775a746feb21c598d60de817c79e35b.png

2.6. 输出适配器

输出适配器主要以 ORM 框架为主,同时各类 ORM 框架均提供了类型映射的扩展点,通过该扩展点可以对 CommonEnum 使用 code 进行存储。

2.6.1. MyBatis 支持

MyBatis 作为最流行的 ORM 框架,提供了 TypeHandler 用于处理自定义的类型扩展。

@MappedTypes(NewsStatus.class)
public class MyBatisNewsStatusHandler extends CommonEnumTypeHandler<NewsStatus> {
    public MyBatisNewsStatusHandler() {
        super(NewsStatus.values());
    }
}

MyBatisNewsStatusHandler 通过 @MappedTypes(NewsStatus.class) 对其进行标记,以告知框架该 Handler 是用于 NewsStatus 类型的转换。

CommonEnumTypeHandler 是为 CommonEnum 提供的通用转化能力,具体如下:

public abstract  class CommonEnumTypeHandler<T extends Enum<T> & CommonEnum>
        extends BaseTypeHandler<T> {
    private final List<T> commonEnums;

    protected CommonEnumTypeHandler(T[] commonEnums){
        this(Arrays.asList(commonEnums));
    }

    protected CommonEnumTypeHandler(List<T> commonEnums) {
        this.commonEnums = commonEnums;
    }

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i, t.getCode());
    }

    @Override
    public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException {

        int code = resultSet.getInt(columnName);
        return commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }

    @Override
    public T getNullableResult(ResultSet resultSet, int i) throws SQLException {
        int code = resultSet.getInt(i);
        return commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }

    @Override
    public T getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        int code = callableStatement.getInt(i);
        return commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }
}

由于逻辑比较简单,在此不做过多解释。

有了类型之后,需要在 spring boot 的配置文件中指定 type-handler 的加载逻辑,具体如下:

mybatis:
  type-handlers-package: com.geekhalo.lego.enums.mybatis

完成配置后,使用 Mapper 对数据进行持久化,数据表中存储的便是 code 信息,具体如下:

e31b1466dcf5fcbead8ae0e4b97eb193.png
2.6.2. JPA 支持

随着 Spring data 越来越流行,JPA 又焕发出新的活力,JPA 提供 AttributeConverter 以对属性转换进行自定义。

首先,构建 JpaNewsStatusConverter,具体如下:

public class JpaNewsStatusConverter extends CommonEnumAttributeConverter<NewsStatus> {
    public JpaNewsStatusConverter() {
        super(NewsStatus.values());
    }
}

CommonEnumAttributeConverter 为 CommonEnum 提供的通用转化能力,具体如下:

public abstract class CommonEnumAttributeConverter<E extends Enum<E> & CommonEnum>
        implements AttributeConverter<E, Integer> {
    private final List<E> commonEnums;

    public CommonEnumAttributeConverter(E[] commonEnums){
        this(Arrays.asList(commonEnums));
    }

    public CommonEnumAttributeConverter(List<E> commonEnums) {
        this.commonEnums = commonEnums;
    }

    @Override
    public Integer convertToDatabaseColumn(E e) {
        return e.getCode();
    }

    @Override
    public E convertToEntityAttribute(Integer code) {
        return (E) commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }
}

在有了 JpaNewsStatusConverter 之后,我们需要在 Entity 的属性上增加配置信息,具体如下:

@Entity
@Data
@Table(name = "t_jpa_news")
public class JpaNewsEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Convert(converter = JpaNewsStatusConverter.class)
    private NewsStatus status;
}

@Convert(converter = JpaNewsStatusConverter.class) 是对 status 的配置,使用 JpaNewsStatusConverter 进行属性的转换。

运行持久化指令后,数据库如下:

c42e88a565b838edde1e8a5ae2089cb0.png

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

3. 项目信息

项目仓库地址:https://gitee.com/litao851025/lego



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

36cd8b18d999bb5db30a55af63ead132.png

已在知识星球更新源码解析如下:

5628cc7aadf96459faba43ca019bc782.jpeg

b2d15fb3cd8381f5cf882c7a960d82ba.jpeg

213161d57c8edfefef38f0ae4f45cef5.jpeg

263533d7a0a0c10caccce4dc03ae5adb.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
Java枚举高级用法:实现接口与定义抽象方法 本文深入探讨了Java枚举的高级用法,重点介绍了枚举实现接口和定义抽象方法两大特性。通过代码示例展示了枚举如何实现单个或多个接口,以及通过抽象方法让每个枚举常量拥有独立行为。文章还对比了不同实现方式的优缺点,分析了适用场景,并提供了结合字段、构造函数的综合应用示例。最后简要提及性能考量,指出带抽象方法的枚举比简单枚举略慢约8.7%,但带来的灵活性优势远超微小性能损失。这些高级特性使枚举不仅能表示常量,还能实现多态行为,大大增强了代码的表达能力和可维护性。 阅读详情

相关推荐

升级版 @Async,让异步任务无懈可击

Spring 的 @Async 注解,想必大家都非常熟悉,只需在方法上增加 @Aysnc ,便可以将其转化为异步操作,任务在后台线程池中运行。在日常开发过程中,像记录日志这种非核心业务,才允许使用 Spring 的 Async 进行异步化,其他场景需要使用更加完备的 MQ 方案。由于数据存储于内存,服务重启存在任务丢失问题,所以,只适用于要求不太严谨的业务,对于要求严格的场景,只能另选方案。为 @AsyncBasedRocketMQ 注解方法,增加消息拦截,并启动 并行消费者 进行消息消费;

m0_71777195的博客 397

枚举实现接口

  一、枚举概述        创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum&lt;E extends Enum&lt;E&gt;&gt;,而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name...

博茨瓦纳的狮王 4480

项目中如何优雅的使用枚举类型

本文主要介绍了项目中使用枚举的优缺点,并针对缺点给出了解决方案,解决了枚举在项目中全自动转换,避免了频繁转换的问题

赵侠客 1531

stream的三个常用方式(toMap,groupingBy,findFirst)

stream的三个常用方式(toMap,groupingBy,findFirst)前言一、stream().findFirst().orElse(null)二、toMap三、groupingBy四、Lists.newArrayList()总结 前言 时间点:2022年3月 离开成都来到上海,有幸遇到了现在的leader,编码思维得到了进一步的开拓。 现将4月份的总结记录起来。 一、stream().findFirst().orElse(null) 最简单开始: 1:查询/删除时,接口入参最好写成批量的(

qq_37700773的博客 1万+

mybatis-plus-enum实现枚举类型自动转换:优雅处理枚举值映射和分页

通过在实体类枚举字段上添加 @EnumValue 注解,开发者可以轻松地实现枚举值与数据库字段的映射,避免了手动转换的繁琐步骤。注解是MyBatis Plus提供的一种注解,用于标识实体类中的枚举字段,指定枚举值与数据库字段之间的映射关系。pagehelper的数据库没配置好, 数据库类型修改为。是Mybatis-plus 下的枚举转换,要在。实现枚举值与数据库字段的映射。

专注于计算机研发知识和资讯分享 2156

MRI脑影像分析从哲学到技术:一文搞懂VBM预处理基本原理(全网最详细解析)

   分析大脑解剖学差异最常用方法之一是基于体素的形态学方法(voxel-based morphometry, VBM)。 VBM的基本思想是测量大脑组织,尤其是灰质的局部浓度的差异。在大脑的每个体素处进行操作,然后在两个或多个实验组之间进行统计比较,从而在受调查的组之间建立特定大脑区域中脑组织浓度的统计学显着差异。 VBM分析基于(高分辨率)MRI脑部扫描,涉及大量处理步骤,主要是空间归一化,分割,平滑和统计分析,最终结果是统计图,显示了各组之间组织类型明显不同的区域[^1]。 参考 [^1] ..

意疏的学习笔记 3万+

Java枚举类型定义的优雅方式enum

我比较偏向于这样定义枚举类型。 /** * 下载服务器ip变化状态枚举 * Created by elle on 2019/2/19. */ public enum DownloadSerIpChangeStatus { IGNORE("ignore", "忽略"), CHANGED("changed", "已改变"), ERROR("error", "错误"); pri

天线婊婊的博客 3225

Matplotlib图片尺寸调整全攻略:从figsize到savefig的实战技巧

在数据可视化与科学计算中,图形尺寸控制是影响图表可读性与专业度的基础环节。其核心原理在于协调逻辑尺寸(英寸)与物理输出(像素)的映射关系,这直接决定了信息呈现的清晰度与布局合理性。从技术价值看,精准的尺寸控制能提升图表在不同媒介(如学术论文、报告、网页)中的适配性,避免显示不全、模糊失真等常见问题。在应用场景上,无论是Jupyter Notebook中的交互探索、自动化报告的批量生成,还是满足严格出版要求的插图制作,都需要掌握对应的尺寸调整策略。本文聚焦于matplotlib中的figsize参数、rcPa

weixin_30899023的博客 327

【Java】枚举类型

枚举类型是一种特殊的数据类型,用于定义一组固定的命名常量。枚举类型提供了一种更强大、更安全和更易读的方式来表示一组相关的常量。在Java中,枚举类型是通过使用enum关键字来定义的。枚举类型可以包含一个或多个枚举常量,每个常量都是枚举类型的实例。枚举常量是在枚举类型中预先定义的,它们是唯一的、已命名的对象。

qq_61635026的博客 2万+

深度残差网络的无人机多目标识别

深度残差网络的无人机多目标识别 人工智能技术与咨询 来源:《图学学报》。作者翟进有等 摘要:传统目标识别算法中,经典的区域建议网络(RPN)在提取目标候选区域时计算量大,时间复杂度较高,因此提出一种级联区域建议网络(CRPN)的搜索模式对其进行改善。此外,深层次的卷积神经网络训练中易产生退化现象,而引入残差学习的深度残差网络(ResNet),能够有效抑制该现象。对多种不同深度以及不同参数的网络模型进行研究,将两层残差学习模块与三层残差学习模块结合使用,设计出一种占用内存更小、时间复杂度更低的新型多捷.

m0_62870606的博客 3106

第七章 Wi-Fi连接过程

系列文章目录 第一章 国内下载AOSP最新源码的方法 第二章 下载AOSP WiFi相关的代码 第三章 将源码导入Android Studio(无需编译idegen) 文章目录系列文章目录前言一、Wi-Fi连接是什么?二、Wi-Fi连接的过程1. 手动连接总结 前言 Wi-Fi连接分为下面几种过程,每种的流程都有些许差异: 手动连接 自动连接 在BSS之间漫游 Passpoint热点连接 一、Wi-Fi连接是什么? Wi-Fi连接是指STA(手机)连接到AP(无线路由器)的过程,这个过程分为链路

Frank.Zhang的专栏 2526

求你了,不要再在对外接口中使用枚举类型了!

今日推荐减少 try-catch ,这样做才叫优雅! 让人上瘾的新一代开发神器,彻底告别Controller、Service、Dao等方法 SpringBoot实现人脸识别功能 相信我,使用 Stream 真的可以让代码更优雅! 全网最详细的线程池 ThreadPoolExecutor 解读! 利用多线程批量拆分 List 导入数据库,效率杠杠的!今天端午节,点...

好好学java 318

改进爬山算法之六:随机重启爬山算法(Random-Restart Hill Climbing,RRHC)

随机重启爬山算法(Random-Restart Hill Climbing,RRHC)是爬山算法的一种改进策略,是一种启发式搜索算法,旨在通过随机重启来克服传统爬山算法容易陷入局部最优解的局限性,并增加找到全局最优解的概率。随机重启爬山算法通过在多次运行中不断尝试不同的初始解,并在每次运行中执行标准的爬山算法,最终选择所有运行中找到的最佳解作为最终结果。(1)计算复杂度:由于需要多次运行爬山算法,因此算法的计算复杂度可能较高,特别是在解空间较大或每次迭代需要较长时间的情况下。

搏博的专栏 2204

【Java系列】深入解析枚举类型

Java 枚举(Enum)是一种特殊的数据类型,它是一组预定义的常量,每个常量都有一个名称和一个值。 枚举类型在 Java 中被广泛使用,它可以用来代替常量、标志位、状态码等,使代码更加清晰、易读和易维护。

颜淡慕潇 2万+

[QMT量化交易小白入门]-105、震荡市最适合的策略:ETF多标的动态网格策略,回测年化收益47.81%

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写200篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

木头大左的博客 2060

【从零开始vnpy量化投资】十一. 实盘接入测试与正式实盘

本篇主要讲解如何使用vnpy进行实盘交易,由于上一节我们已经学习了模拟盘运行,如果一切顺利的话,只需要通过穿透测试,就可以正式部署实盘了。

魔落的博客 4229

Golang | 优雅地定义枚举类型

在优雅的定义枚举方法中,我们需要使用到“iota”关键字。iota的初始值为0,并且会自动增长。iota不仅限于定义单个常量的枚举值,还可以定义多个。代码示例e , f) // 我们打印出他们的结果为:1,2,3,4,5,6我们也可以试图在中途使用等式去改变表达式的值。最好使用打印语句验证自己的分析是否正确。代码示例:e , f。

y943711797的博客 1746

零基础入门红外与可见光图像融合:DAF-Net 实战全指南

本文介绍了基于DAF-Net的红外与可见光图像融合技术,主要内容包括:技术原理、环境配置、数据准备和模型实现。DAF-Net通过双分支特征提取和动态注意力融合机制,有效结合红外图像的热辐射信息与可见光图像的纹理细节。文章详细讲解了开发环境搭建步骤(Python 3.8+PyTorch),TNO数据集的预处理方法,并提供了完整的DAF-Net实现代码,包含特征提取、注意力融合和图像重建三个关键模块。该技术可广泛应用于安防监控、自动驾驶等领域,帮助开发者快速入门多模态图像融合。

FJN110的博客 123

MyBatis EnumTypeHandler:优雅地处理枚举类型

在数据库与 Java 对象之间映射时,枚举类型的处理往往是一个常见的挑战,因为数据库通常存储的是枚举值的名称或者序号,而 Java 枚举对象则需要将这些值映射到具体的枚举实例上。是 MyBatis 中一个重要的类型处理器,它提供了一种优雅且高效的方式来处理 Java 枚举类型与数据库之间的映射。元数据(如枚举常量的名称或序号),将数据库中的值映射到相应的枚举实例上。,我们可以轻松地将数据库中的值映射到 Java 枚举实例上,或者将 Java 枚举实例映射到数据库能够识别的值上。在实际项目中,合理地使用。

wddblog的博客 1849

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

优雅地使用枚举参数,让项目Spring Boot项目更加优雅

1.引言在开发 Spring Boot 应用时,我们常常需要使用枚举(Enum)类型来表示一组常量,比如状态、类型、角色等。Spring Boot 提供了多种方式来优雅地处理和使用枚举类型,尤其是当它们作为方法参数、请求参数或者返回值时。使用枚举的好处是可以避免魔法值(magic numbers)和硬编码字符串,同时使代码更加可读和易于维护。本文将深入探讨如何在 Spring Boot 项目...

java思维导图 1572

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

枚举类型enum用法_Golang 枚举使用

Go 语言没有 enum 关键字的,通过使用 const & iota 可以实现枚举的能力。本篇文章将探讨几个问题:为什么要使用枚举,没了它就不行嘛?如何在 Go 语言中优雅的使用枚举。为什么要使用枚举?Stackoverflow 上有个问题 What are enums and why are they useful? 中的回答很具备说服力。 当一个变量(尤其是一个方法的参数)仅能取自一...

weixin_39821718的博客 2386

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

枚举类型:常量集合的优雅管理

在编程中,常量是不可或缺的元素,它们代表固定值,如状态码、方向或配置选项。在 JavaScript 中,我们常使用对象或变量来模拟常量,但这容易导致拼写错误或值重复。TypeScript 的枚举类型正是为此而生:它允许开发者定义一组命名常量,并通过类型系统确保使用时的安全性。

zimin的专栏 565

SpringBoot--在Entity(DAO)中使用枚举类型

本文介绍SpringBoot如何在Entity(DAO)中使用枚举类型。 在实际开发中,经常会遇到表示类型或者状态的情况,比如:有三种支付方式:微信、支付宝、银联。本文介绍如何用枚举来表示,枚举是这种场景最好的方案(枚举本身就是为了表示可穷举类型而发明出来的!)。

IT利刃出鞘的博客 3894

mybatis枚举类型转换器详解

1. 前言 刚入手spring-boot还不太熟练,先弄了个空的框架,然后写了个简单的用户查询,没啥挑战性。然后想起来之前一直对枚举不太了解,而用户的性别正好可以用枚举类型来表示(male, female)。于是就开始了自己的挖坑之旅。 本文主要分为三个部分: mybatis自带枚举类型转换 自定义枚举类型转换 mybatis类型转换深入理解(将在下一篇介绍) 2. mybatis自带枚举类...

intersting的博客 9029

Java中枚举类型的校验

最近项目中用到了一些枚举类,而接口API中提供的是String类型来接收,这样的话,调用方随便传什么,如果传的并不是后台定义的枚举类型,那么处理起来肯定会有问题。所以我们需要对调用方传来的枚举进行校验。 简单粗暴的方法就是,拿传入的参数跟枚举类型一个个比较,直到找到相同的才认为输入的值合法。这样的话需要写很多的if else来判断。那有没有优雅点的处理方式呢? 之前写过一篇通过注解校验参数的博...

Lieforlove的博客 9258
上一篇: 美团:为什么 MySQL 不推荐使用 join?
下一篇: 分布式定时任务框架选型,写的太好了 !
公众号-芋道源码
博客等级 码龄10年 1625粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值