使用enum.values()与String数组时是否有性能损失?

时间:2010-03-15 09:42:40

标签: java performance enums

我正在使用枚举来替换我的java应用程序中的String常量(JRE 1.5)。

当我将enum视为不断调用的方法中的静态名称数组时(例如,在呈现UI时),是否会影响性能?

我的代码看起来有点像这样:

public String getValue(int col) {
  return ColumnValues.values()[col].toString();
}

澄清:

  • 我担心与重复枚举values()相关的隐藏费用(例如内部paint()方法)。
  • 我现在可以看到我的所有方案都包含一些int => enum转换 - 这不是Java的方式。

提取values()数组的实际价格是多少?这甚至是个问题吗?

Android开发者

阅读下面的Simon Langhoff的答案,Geeks On Hugs在接受的答案评论中已经指出了这一点。 Enum.values() 必须做一份防御性副本

7 个答案:

答案 0 :(得分:16)

Enum.values()为您提供了对数组的引用,并且遍历一个枚举数组的成本与迭代字符串数组相同。同时,将枚举值与其他枚举值进行比较实际上可以更快将字符串与字符串进行比较。

同时,如果您担心调用values()方法的成本与已经引用数组的成本相比,请不要担心。 Java中的方法调用(现在)非常快,并且无论何时它对性能都很重要,无论如何,编译器都会内联方法调用。

所以,严肃地说,不要担心它。转而专注于代码可读性,并使用Enum以便编译器在尝试使用常量值时捕获它您的代码不希望处理。


如果您对为什么枚举比较可能比字符串比较更快感兴趣,请参阅以下详细信息:

这取决于字符串是否为interned。对于Enum个对象,系统中每个枚举值始终只有一个实例,因此每次调用Enum.equals()都可以非常快速地完成,就像使用==一样运算符而不是equals()方法。实际上,对于Enum个对象,使用==而不是equals()是安全的,而 则不能安全地使用字符串。

对于字符串,如果字符串已被实习,则比较与Enum一样快。但是,如果字符串尚未被实现,则String.equals()方法实际上需要遍历两个字符串中的字符列表,直到其中一个字符串结束或发现两个字符串之间不同的字符。

但同样,这可能无关紧要,即使在Swing呈现必须快速执行的代码中也是如此。 : - )


@Ben Lings指出Enum.values()必须做一个防御性副本,因为数组是可变的,你可以替换Enum.values()返回的数组中的值。这意味着您必须考虑该防御性副本的成本。但是,复制单个连续数组通常是一种快速操作,假设它是使用某种内存复制调用“在引擎盖下”实现的,而不是天真地迭代数组中的元素。所以,我认为这不会改变最终答案。

答案 1 :(得分:14)

对于枚举,为了保持不变性,每次调用Values()方法时,它们都会克隆后备数组。这意味着它会对性能产生影响。多少取决于您的具体情况。

我一直在监控自己的Android应用,发现这个简单的调用在我的特定情况下使用了13.4% CPU time!

为了避免克隆values数组,我决定简单地将值缓存为私有字段,然后在需要时循环遍历这些值:

private final static Protocol[] values = Protocol.values();

经过这个小优化之后,我的方法调用仅占用了可忽略不计的0.0% CPU time

在我的用例中,这是一个受欢迎的优化,但是,重要的是要注意使用这种方法是对枚举的可变性的权衡。一旦你给它们一个参考,谁知道人们可能会把它放到你的数组中呢?

答案 2 :(得分:2)

根据经验:在考虑优化之前,您是否知道此代码可能会降低您的应用程序速度?

现在,事实。

在很大程度上,枚举是分散在编译过程中的语法糖。因此,为枚举类定义的values方法返回一个静态集合(也就是说在类初始化时加载),其性能可以被认为大致相当于数组1。

答案 3 :(得分:2)

如果您担心表现,请进行衡量。

从代码中,我不会指望任何意外,但90%的性能猜测是错误的。如果您想要安全,请考虑将枚举移到调用代码中(即public String getValue(ColumnValues value) {return value.toString();})。

答案 4 :(得分:2)

使用它:

private enum ModelObject { NODE, SCENE, INSTANCE, URL_TO_FILE, URL_TO_MODEL,
    ANIMATION_INTERPOLATION, ANIMATION_EVENT, ANIMATION_CLIP, SAMPLER, IMAGE_EMPTY,
    BATCH, COMMAND, SHADER, PARAM, SKIN }
private static final ModelObject int2ModelObject[] = ModelObject.values();

答案 5 :(得分:1)

如果您只是为了查找特定值来迭代枚举值,则可以将枚举值静态映射到整数。这会对性能负载产生性能影响,并且可以根据映射的参数轻松/低影响地获取特定的枚举值。

public enum ExampleEnum {
    value1(1),
    value2(2),
    valueUndefined(Integer.MAX_VALUE);

    private final int enumValue;
    private static Map enumMap;
    ExampleEnum(int value){
       enumValue = value;
    }
    static {
       enumMap = new HashMap<Integer, ExampleEnum>();
       for (ExampleEnum exampleEnum: ExampleEnum.values()) {
           enumMap.put(exampleEnum.value, exampleEnum);
        }
    }
    public static ExampleEnum getExampleEnum(int value) {
        return enumMap.contains(value) ? enumMap.get(value) : valueUndefined;
    }
}

答案 6 :(得分:-1)

我想是的。并且使用常量更方便。