猿问

通过添加 Enum 静态 Holder 进行优化

我想知道添加Enum一个静态 Holder 是否总是比“get”Enum 方法(或类似用于获取特定 Enum 值)上的迭代值更好的实现。


例如对于 Spring HttpStatus当前实现:


HttpStatus(int value, String reasonPhrase) {

    this.value = value;

    this.reasonPhrase = reasonPhrase;

}

public static HttpStatus valueOf(int statusCode) {

    for (HttpStatus status : values()) {

        if (status.value == statusCode) {

            return status;

        }

    }

    throw new IllegalArgumentException("No matching constant for [" + statusCode + "]");

}

可以通过以下方式优化:


private static class Holder {

    private static Map<Integer, HttpStatus> enumMap = new HashMap<>();

}


HttpStatus(int value, String reasonPhrase) {

    this.value = value;

    this.reasonPhrase = reasonPhrase;

    Holder.enumMap.put(value, this);

}


public static HttpStatus valueOf(int statusCode) {

     return Holder.enumMap.computeIfAbsent(statusCode, statusCode -> {

            throw new IllegalArgumentException("No matching constant for [" + statusCode + "]"); });

}

代码优化:


循环版本具有线性时间复杂度(每个获取值的请求),而使用 HashMap 的版本具有 O(1) 的时间复杂度。


这个优化是否有我遗漏的缺陷?


炎炎设计
浏览 166回答 2
2回答

呼啦一阵风

我很久以前就检查过这种方法,我决定使用手动代替循环值没有任何好处Map。地图发生在内存中要使 map with&nbsp;O(1)search 确实比O(n)手动循环好,enum 应该有 1000 多个常量(这是实验数字)。但根据我的经验,我有最多 200 多个常量的枚举国家。在最坏的情况下,这也不是整个应用程序的瓶颈。我总是使用手动循环并且不担心性能。许多序列化框架(如 Jackson 将 enum 转换为 json)使用Enum.valueOf().

DIEA

要记住的一件事是,一旦初始化,静态地图将无限期地保存在内存中;循环方法只会values()在循环迭代期间保存通过调用创建的数组。但是,值得指出的是,使用 holder 类没有任何优势:因为您是在构造函数中添加到映射中的,所以在调用构造函数时会立即初始化 holder 类。因此,您也可以使用普通的旧静态(最终)字段。同样值得考虑的是,这种方法必然要求映射是可变的。您可能不打算对其进行变异,但是防御性地改变方法是值得的,这样您就不能。相反,您可以直接在字段上初始化:static final Map<Integer, HttpStatus> map =&nbsp;&nbsp; &nbsp; Collections.unmodifiableMap(&nbsp; &nbsp; &nbsp; &nbsp; Stream.of(HttpStatus.values())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .collect(toMap(s -> s.value,&nbsp; s -> s)));(或使用类似 Guava 的东西ImmutableMap)关于直接初始化映射的方法的另一点是它不会在构造函数中添加到映射中——这意味着您实际上不必将其放入枚举类本身。这使您可以灵活地在无法更改代码的枚举上使用它,和/或仅将地图添加到您发现有性能需求的地方。
随时随地看视频慕课网APP

相关分类

Java
我要回答