Java Enum.values() 与 EnumSet.allOf()。哪个更可取?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2464950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Enum.values() vs EnumSet.allOf( ). Which one is more preferable?
提问by Alexander Pogrebnyak
I looked under the hood for EnumSet.allOf
and it looks very efficient, especially for enums with less than 64 values.
我查看了引擎盖EnumSet.allOf
,它看起来非常有效,尤其是对于值小于 64 的枚举。
Basically all sets share the single array of all possible enum values and the only other piece of information is a bitmask which in case of allOf
is set in one swoop.
基本上所有的集合都共享所有可能的枚举值的单个数组,唯一的其他信息是一个位掩码,以防万一allOf
是一次性设置的。
On the other hand Enum.values() seems to be a bit of black magic. Moreover it returns an array, not a collection, so in many cases it must be decorated with Arrays.asList( ) to be usable in any place that expects collection.
另一方面 Enum.values() 似乎有点黑魔法。此外,它返回一个数组,而不是一个集合,因此在许多情况下,它必须用 Arrays.asList() 修饰才能在任何需要集合的地方使用。
So, should EnumSet.allOf
be more preferable to Enum.values
?
那么,应该EnumSet.allOf
更可取Enum.values
吗?
More specifically, which form of for
iterator should be used:
更具体地说,for
应该使用哪种形式的迭代器:
for ( final MyEnum val: MyEnum.values( ) );
or
或者
for ( final MyEnum val: EnumSet.allOf( MyEnum.class ) );
采纳答案by Alexander Pogrebnyak
Because I did not receive the answer to my question on which one is more efficient, I've decided to do some testing of my own.
因为我没有收到关于哪个更有效的问题的答案,所以我决定自己做一些测试。
I've tested iteration over values()
, Arrays.asList( values() )
and EnumSet.allOf( )
.
I've repeated these tests 10,000,000 times for different enum sizes. Here are the test results:
我已经测试了values()
,Arrays.asList( values() )
和 的迭代EnumSet.allOf( )
。对于不同的枚举大小,我已经将这些测试重复了 10,000,000 次。以下是测试结果:
oneValueEnum_testValues 1.328
oneValueEnum_testList 1.687
oneValueEnum_testEnumSet 0.578
TwoValuesEnum_testValues 1.360
TwoValuesEnum_testList 1.906
TwoValuesEnum_testEnumSet 0.797
ThreeValuesEnum_testValues 1.343
ThreeValuesEnum_testList 2.141
ThreeValuesEnum_testEnumSet 1.000
FourValuesEnum_testValues 1.375
FourValuesEnum_testList 2.359
FourValuesEnum_testEnumSet 1.219
TenValuesEnum_testValues 1.453
TenValuesEnum_testList 3.531
TenValuesEnum_testEnumSet 2.485
TwentyValuesEnum_testValues 1.656
TwentyValuesEnum_testList 5.578
TwentyValuesEnum_testEnumSet 4.750
FortyValuesEnum_testValues 2.016
FortyValuesEnum_testList 9.703
FortyValuesEnum_testEnumSet 9.266
These are results for tests ran from command line. When I ran these tests from Eclipse, I got overwhelming support for testValues
. Basically it was smaller than EnumSet
even for small enums. I believe that the performance gain comes from optimization of array iterator in for ( val : array )
loop.
这些是从命令行运行的测试的结果。当我从 Eclipse 运行这些测试时,我得到了对testValues
. 基本上它EnumSet
甚至比小型枚举还要小。我相信性能提升来自for ( val : array )
循环中数组迭代器的优化。
On the other hand, as soon as you need a java.util.Collection to pass around, Arrays.asList( )
looses over to EnumSet.allOf
, especially for small enums, which I believe will be a majority in any given codebase.
另一方面,一旦你需要一个 java.util.Collection 来传递,就会Arrays.asList( )
松散到EnumSet.allOf
,特别是对于小枚举,我相信这将是任何给定代码库中的大多数。
So, I would say you should use
所以,我会说你应该使用
for ( final MyEnum val: MyEnum.values( ) )
but
但
Iterables.filter(
EnumSet.allOf( MyEnum.class ),
new Predicate< MyEnum >( ) {...}
)
And only use Arrays.asList( MyEnum.values( ) )
where java.util.List
is absolutely required.
并且只Arrays.asList( MyEnum.values( ) )
在java.util.List
绝对需要的地方使用。
回答by Peter Lawrey
You should use the approach which is simplest and clearest to you. Performance shouldn't be a consideration in most situations.
您应该使用对您来说最简单、最清晰的方法。在大多数情况下,不应考虑性能。
IMHO: neither option performs very well as they both create objects. One in the first case and three in the second. You could construct a constant which holds all the values for performance reasons.
恕我直言:这两个选项的性能都不是很好,因为它们都创建了对象。第一种情况下一个,第二种情况下三个。出于性能原因,您可以构造一个常量来保存所有值。
回答by Arne Burmeister
The values()
method is more clear and performant if you just want to iterate over all possible enum values. The values are cached by the class (see Class.getEnumConstants()
)
values()
如果您只想迭代所有可能的枚举值,该方法会更加清晰和高效。值由类缓存(请参阅Class.getEnumConstants()
)
If you need a subset of values, you should use an EnumSet
. Start with allOf()
or noneOf()
and add or remove values or use just of()
as you need.
如果您需要值的子集,则应使用EnumSet
. 从allOf()
or开始,noneOf()
添加或删除值或of()
根据需要使用。
回答by Enno Shioji
Not that I went through the entire implementation, but it seems to me that EnumSet.allOf() is basically using the same infrastructure as .values(). So I'd expect EnumSet.allOf() requires some (probably negligible) additional steps (see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6276988).
并不是说我经历了整个实现,但在我看来 EnumSet.allOf() 基本上使用与 .values() 相同的基础结构。所以我希望 EnumSet.allOf() 需要一些(可能可以忽略不计)额外的步骤(参见http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6276988)。
It seems clear to me that the intended use of foreach is for(MyEnum val : MyEnum.values())
why do it differently? You will only confuse the maintenance programmer.
我似乎很清楚 foreach 的预期用途是for(MyEnum val : MyEnum.values())
为什么要这样做?你只会混淆维护程序员。
I mean, if you need a collection, you should get one. If you want to use a foreach, arrays are good enough. I'd even prefer arrays if pressed! Why wrap anything with anything, if what you got (array) is good enough? Simple things are normally faster.
我的意思是,如果你需要一个收藏,你应该得到一个。如果你想使用 foreach,数组就足够了。如果按下,我什至更喜欢数组!如果你得到的(数组)足够好,为什么要用任何东西包装任何东西?简单的事情通常更快。
In anyways, Peter Lawrey is right. Don't bother about the performance of this.. It's fast enough, and chances are there are million other bottlenecks that render that tiny theoretical performance difference as totally irrelevant (Don't see his "object creation" point though. To me the first example seems to be 100% OK).
无论如何,彼得劳瑞是对的。不要担心它的性能..它足够快,并且可能还有数百万其他瓶颈使这种微小的理论性能差异完全无关紧要(尽管不要看到他的“对象创建”点。对我来说第一个示例似乎是 100% OK)。
回答by irreputable
There is also Class.getEnumConstants()
还有 Class.getEnumConstants()
under the hood they all call values()
methods of enum types anyway, through reflection.
在幕后,他们都通过反射调用values()
枚举类型的方法。
回答by YoYo
EnumSet
is not built with the intention to iterate over it's values. Rather it is implemented with the idea for it to represent a BitMap or BitMask efficiently (or reasonably efficient). The javadoc on EnumSet
also states:
EnumSet
不是为了迭代它的值而构建的。相反,它的实现是为了有效地(或合理地有效)表示位图或位掩码。上的javadocEnumSet
还指出:
Enum sets are represented internally as bit vectors. This representation is extremely compact and efficient. The space and time performance of this class should be good enough to allow its use as a high-quality, typesafe alternative to traditional int-based "bit flags." Even bulk operations (such as containsAll and retainAll) should run very quickly if their argument is also an enum set.
枚举集在内部表示为位向量。这种表示非常紧凑和高效。这个类的空间和时间性能应该足够好,可以将其用作传统的基于 int 的“位标志”的高质量、类型安全的替代品。如果它们的参数也是枚举集,即使是批量操作(例如 containsAll 和 retainAll)也应该运行得非常快。
Because only one single bit can represent a certain Enum value, it is also implemented as a Set
and not as a List
.
因为只有一位可以表示某个 Enum 值,所以它也被实现为 aSet
而不是 a List
。
Now, it is probably also true that you can accomplish the same, and faster, using C-style bit masks (x^2), however it offers a more intuitive coding style and type safe use using enums, and it expands easily beyond the size of what an int
or long
can contain.
现在,使用 C 样式位掩码 (x^2) 也可以更快地完成相同的操作,这可能也是正确的,但是它使用枚举提供了更直观的编码风格和类型安全使用,并且它很容易扩展到超出int
或long
可以包含的内容的大小。
As such you can test that all bits are set as follows:
因此,您可以测试所有位是否设置如下:
public class App {
enum T {A,B}
public static void main(String [] args) {
EnumSet<T> t = EnumSet.of(T.A);
t.containsAll(EnumSet.allOf(T.class));
}
}