使用 enum.values() 与字符串数组相比,性能是否会受到影响?

发布于 2024-08-25 22:38:09 字数 636 浏览 6 评论 0原文

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

当我在不断调用的方法中将枚举视为名称的静态数组时(例如渲染 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() 必须进行防御性复制

I'm using enumerations to replace String constants in my java app (JRE 1.5).

Is there a performance hit when I treat the enum as a static array of names in a method that is called constantly (e.g. when rendering the UI)?

My code looks a bit like this:

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

Clarifications:

  • I'm concerned with a hidden cost related to enumerating values() repeatedly (e.g. inside paint() methods).
  • I can now see that all my scenarios include some int => enum conversion - which is not Java's way.

What is the actual price of extracting the values() array? Is it even an issue?

Android developers

Read Simon Langhoff's answer below, which has pointed out earlier by Geeks On Hugs in the accepted answer's comments. Enum.values() must do a defensive copy

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

双马尾 2024-09-01 22:38:09

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

我一直在监控我自己的Android应用程序,发现这个简单的调用使用了 13.4% CPU 时间! 在我的具体情况下。

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

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

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

在我的用例中,这是一个受欢迎的但是,重要的是要注意,使用这种方法是对枚举的可变性进行权衡。谁知道一旦您给他们提供了对值数组的引用,人们就会将什么内容放入您的值数组中!?

For enums, in order to maintain immutability, they clone the backing array every time you call the Values() method. This means that it will have a performance impact. How much depends on your specific scenario.

I have been monitoring my own Android app and found out that this simple call used 13.4% CPU time! in my specific case.

In order to avoid cloning the values array, I decided to simple cache the values as a private field and then loop through those values whenever needed:

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

After this small optimisation my method call only hogged a negligible 0.0% CPU time

In my use case, this was a welcome optimisation, however, it is important to note that using this approach is a tradeoff of mutability of your enum. Who knows what people might put into your values array once you give them a reference to it!?

温暖的光 2024-09-01 22:38:09

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

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

所以,说实话,不用担心。而是专注于代码的可读性,并使用Enum,这样如果您尝试使用常量值,编译器就会捕获它您的代码不希望处理。


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

这取决于字符串是否已 实习与否。对于 Enum 对象,系统中每个枚举值始终只有一个实例,因此每次调用 Enum.equals() 都可以非常快地完成,就像如果您使用 == 运算符而不是 equals() 方法。事实上,对于 Enum 对象,使用 == 代替 equals() 是安全的,但不是可以安全地使用字符串。

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

但同样,这可能并不重要,即使在必须快速执行的 Swing 渲染代码中也是如此。 :-)


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

Enum.values() gives you a reference to an array, and iterating over an array of enums costs the same as iterating over an array of strings. Meanwhile, comparing enum values to other enum values can actually be faster that comparing strings to strings.

Meanwhile, if you're worried about the cost of invoking the values() method versus already having a reference to the array, don't worry. Method invocation in Java is (now) blazingly fast, and any time it actually matters to performance, the method invocation will be inlined by the compiler anyway.

So, seriously, don't worry about it. Concentrate on code readability instead, and use Enum so that the compiler will catch it if you ever try to use a constant value that your code wasn't expecting to handle.


If you're curious about why enum comparisons might be faster than string comparisons, here are the details:

It depends on whether the strings have been interned or not. For Enum objects, there is always only one instance of each enum value in the system, and so each call to Enum.equals() can be done very quickly, just as if you were using the == operator instead of the equals() method. In fact, with Enum objects, it's safe to use == instead of equals(), whereas that's not safe to do with strings.

For strings, if the strings have been interned, then the comparison is just as fast as with an Enum. However, if the strings have not been interned, then the String.equals() method actually needs to walk the list of characters in both strings until either one of the strings ends or it discovers a character that is different between the two strings.

But again, this likely doesn't matter, even in Swing rendering code that must execute quickly. :-)


@Ben Lings points out that Enum.values() must do a defensive copy, since arrays are mutable and it's possible you could replace a value in the array that is returned by Enum.values(). This means that you do have to consider the cost of that defensive copy. However, copying a single contiguous array is generally a fast operation, assuming that it is implemented "under the hood" using some kind of memory-copy call, rather than naively iterating over the elements in the array. So, I don't think that changes the final answer here.

樱花细雨 2024-09-01 22:38:09

根据经验:在考虑优化之前,您是否有任何线索表明这段代码可能会减慢您的应用程序速度?

现在,事实。

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

As a rule of thumb : before thinking about optimizing, have you any clue that this code could slow down your application ?

Now, the facts.

enum are, for a large part, syntactic sugar scattered across the compilation process. As a consequence, the values method, defined for an enum class, returns a static collection (that's to say loaded at class initialization) with performances that can be considered as roughly equivalent to an array one.

听风念你 2024-09-01 22:38:09

如果您担心性能,请进行测量。

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

If you're concerned about performance, then measure.

From the code, I wouldn't expect any surprises but 90% of all performance guesswork is wrong. If you want to be safe, consider to move the enums up into the calling code (i.e. public String getValue(ColumnValues value) {return value.toString();}).

油焖大侠 2024-09-01 22:38:09

使用这个:

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();

use this:

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();
淡笑忘祈一世凡恋 2024-09-01 22:38:09

如果您只是为了查找特定值而迭代枚举值,则可以将枚举值静态映射到整数。这会增加对类负载的性能影响,并使得根据映射参数获取特定枚举值变得容易/影响较小。

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;
    }
}

If you're iterating through your enum values just to look for a specific value, you can statically map the enum values to integers. This pushes the performance impact on class load, and makes it easy/low impact to get specific enum values based on a mapped parameter.

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;
    }
}
沉鱼一梦 2024-09-01 22:38:09

我想是的。而且使用Constants更方便。

I think yes. And it is more convenient to use Constants.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文