尽信书不如无书之获取枚举值代码优化

简介: 尽信书不如无书之获取枚举值代码优化

1 背景

实际开发中根据枚举的某个属性获取枚举值非常常见。

如定义一个枚举:

@Getter
public enum CoinEnum {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
    CoinEnum(int value) {
        this.value = value;
    }
    private final int value;
}

image.gif

实际开发中经常需要根据 value 的值来获取枚举对象。

那么该怎么做呢?

2 编码

2.1 很low的写法

工作中会见到有采用 switch-case 或者 if-else 实现根据某个属性获取枚举的方式。

类似下面的这种写法:

public static CoinEnum getEnum(int value) {
    switch (value) {
        case 1:
            return PENNY;
        case 5:
            return NICKEL;
        case 10:
            return DIME;
        case 25:
            return QUARTER;
        default:
            return null;
    }
}

image.gif

这种写法最大的问题是如果枚举常量新增、删除、修改等都需要对该函数进行对应的修改,耦合非常高。

不符合开闭原则(开闭原则:对拓展开放,对修改关闭)。

另外如果枚举常量较多,很容易映射错误,后期很难维护。

2.2 改进

我们可以采用枚举类的 values 静态函数获取枚举数组进行匹配,写出一个改进版本的代码:

public static CoinEnum getEnum(int value) {
    for (CoinEnum coinEnum : CoinEnum.values()) {
        if (coinEnum.value == value) {
            return coinEnum;
        }
    }
    return null;
}

image.gif

通过这种改进,后面需要对枚举常量进行修改,该函数不需要改动,显然比之前好了很多。

这种写法在工作中也很常见。

那么是否还有改进空间呢?

这种写法虽然挺不错,但是每次获取枚举对象都要遍历一次枚举数组,时间复杂度是O(n)。

降低时间复杂度该怎么做?一个常见的思路就是空间换时间

2.3 再次优化

因此可以先用map缓存,使用时直接从map中取值。

可以这么优化:

@Getter
public enum CoinEnum {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
    CoinEnum(int value) {
        this.value = value;
    }
    private final int value;
    public int value() {
        return value;
    }
    private static final Map<Integer, CoinEnum> cache = new HashMap<>();
    static {
        for (CoinEnum coinEnum : CoinEnum.values()) {
            cache.put(coinEnum.getValue(), coinEnum);
        }
    }
    public static CoinEnum getEnum(int value) {
        return cache.getOrDefault(value, null);
    }
}

image.gif

通过上面的优化,使用时时间复杂度为 O(1),性能有所提升。

实际开发中能采用这种写法的同学都不太多。

主要原因是网上类似的文章不多这也是很多总爱百度解决问题而不是思考来解决问题的同学进步不大的重要原因

2.4 学无止境

通过上面两次优化,代码的耦合降低了,性能提高了。

所以,可以完美收工了?

NO...

2.3 给出的代码还存在一些问题:

    • 每个枚举类中都需要编写类似的代码,很繁琐。
    • 引入提供上述工具的很多枚举类,如果仅使用枚举常量,也会触发静态代码块的执行。

    还有没有更优雅的方案呢?

    希望大家可以思考一下,给出自己的解决方案。

    具体解决方案参见《阿里巴巴Java开发手册》详解专栏的第 10 节 枚举类的正确学习方式

    3 总结

    既然选择编程这条路,希望大家在提问之前,在百度之前,一定要先有自己的思考。

    校招和社招时,很多大公司的面经非常吸引人,但是对大多数人帮助不大。是因为很多面经只有题目没有答案,好多人会搜索各种答案来背诵,然而很多所谓的标准答案都没有揭露问题的本质,都是不完整的,也不是最佳答案。

    尽信书不如无书,希望大家在读书、看博客、看专栏等过程中更重视对问题的思考,对方法的学习,而是记忆具体知识点。俗话说“授人以鱼不如授人以渔”,希望本文能够启发更多的朋友意识到思考和方法的重要性。

    ----------

    如果你觉得本文对你有帮助,欢迎点赞、评论、转发(注明出处)、关注,你的支持是我创作的最大动力。

    相关文章
    |
    8月前
    |
    Java Spring
    使用枚举定义常量更好点儿
    使用枚举定义常量更好点儿
    |
    8月前
    |
    存储 编译器 Shell
    【C++基础语法 枚举】解析 C/C++ 中枚举类型大小值
    【C++基础语法 枚举】解析 C/C++ 中枚举类型大小值
    104 0
    |
    8月前
    |
    安全 算法 编译器
    【C++基础语法 枚举】C/C++ 中enum枚举量的介绍:介绍enum枚举量在C/C中的作用和使用方法
    【C++基础语法 枚举】C/C++ 中enum枚举量的介绍:介绍enum枚举量在C/C中的作用和使用方法
    109 2
    |
    7月前
    |
    编译器 C语言
    C语言枚举:深入探索下标默认值、自定义值及部分自定义情况
    C语言枚举:深入探索下标默认值、自定义值及部分自定义情况
    |
    8月前
    |
    算法
    枚举算法的介绍
    枚举算法的介绍
    81 0
    |
    Java Spring
    常量or枚举的取舍
    常量or枚举的取舍
    54 0
    |
    存储 编译器 Linux
    关于枚举常量手误带来的错误
    关于枚举常量手误带来的错误
    124 0
    |
    C语言
    C语言 枚举,枚举设置指定值
    数据类型,该整型类型有 6 个数据,默认是从 0 开始,依次递增一个。 yellow 是0 的名字,可以直接使用yellow代替0,yellow 不是变量名,就是一个名字,代表数字0.
    105 0
    C语言——enum枚举实例、知识点。使用枚举,减少相同定义步骤,简洁数据1.1.5
    枚举是C语言常见的一种基本数据类型,它可以避免多个整数定义的麻烦,使代码整洁干净易读如此一看,就觉得繁琐无比,大量重复#define xx明显增加代码量,且数值需自己一一对应而枚举,可以解决这种定义连续数值的过程当变量第一个值未自定义时,第一个枚举成员的默认值则为整型0,后续成员值依次加1,如此时MON=0,TUE=1,WED=2·····.........
    |
    开发框架 数据库
    GoFrame代码优化:使用gconv类型转换 避免重复定义map
    最近一直在研究 GoFrame 框架,经过一段时间的使用、总结、思考,发现确实不失为一款非常值得使用的企业级开发框架。
    447 0

    热门文章

    最新文章