1 背景

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

如定义一个枚举:

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

实际开发中经常需要根据 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;
    }
}

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

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

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

 

2.2 改进

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

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

 

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

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

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

这种写法虽然挺不错,但是每次获取枚举对象都要遍历一次枚举数组,时间复杂度是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);
    }
}

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

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

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

 

2.4 学无止境

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

所以,可以完美收工了?

NO...

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

  • 每个枚举类中都需要编写类似的代码,很繁琐。

  • 引入提供上述工具的很多枚举类,如果仅使用枚举常量,也会触发静态代码块的执行。

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

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

 

 

3 总结

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

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

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