Java HashMap 与 Switch 语句性能对比
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27993819/
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
HashMap vs Switch statement performance
提问by Joe C
A HashMap essentially has O(1) performance while a switch state can have either O(1) or O(log(n)) depending on if the compiler uses a tableswitch or lookup switch.
HashMap 本质上具有 O(1) 性能,而切换状态可以具有 O(1) 或 O(log(n)),具体取决于编译器是使用 tableswitch 还是查找 switch。
Understandably, if a switch statement is written as such,
可以理解,如果 switch 语句是这样写的,
switch (int) {
case 1:
case 2:
case 3:
case 4:
default:
}
then it would use a tableswitch and clearly have a performance advantage over a standard HashMap. But what if the switch statement is sparse? These would be two examples that I would be comparing:
那么它将使用 tableswitch 并且显然比标准 HashMap 具有性能优势。但是如果 switch 语句是稀疏的呢?这将是我要比较的两个例子:
HashMap<Integer, String> example = new HashMap<Integer, String>() {{
put(1, "a");
put(10, "b");
put(100, "c");
put(1000, "d");
}};
.
.
switch (int) {
case 1:
return "a";
case 10:
return "b";
case 100:
return "c";
case 1000:
return "d";
default:
return null;
}
What would provide more throughput, a lookupswitch or HashMap? Does the overhead of the HashMap give the lookupswitch an advantage early but eventually tapers off as the number of cases/entries increase?
什么会提供更多的吞吐量,查找开关或 HashMap?HashMap 的开销是否在早期为查找开关提供了优势,但最终会随着案例/条目数量的增加而逐渐减少?
Edit:I tried some benchmarks using JMH, here are my results and code used. https://gist.github.com/mooman219/bebbdc047889c7cfe612As you guys mentioned, the lookupswitch statement outperformed the HashTable. I'm still wondering why though.
编辑:我使用 JMH 尝试了一些基准测试,这是我使用的结果和代码。https://gist.github.com/mooman219/bebbdc047889c7cfe612正如你们提到的,lookupswitch 语句的性能优于 HashTable。我仍然想知道为什么。
采纳答案by Loc
It depends:
这取决于:
If there are a few items | fixed items. Using switch if you can ( worst case O(n))
If there a a lot of items OR you want to add future items without modifying much code ---> Using hash-map ( access time is considered as constant time)
For your case. You should not worry about performance because the different execution time is very small. Just focus on readability/maintainability of your code. Is it worth to optimize a simple case to improve a few nanoseconds?
如果有几个项目| 固定项目。如果可以,请使用 switch(最坏情况 O(n))
如果有很多项目或者你想在不修改太多代码的情况下添加未来的项目--->使用哈希映射(访问时间被视为常数时间)
对于你的情况。您不应该担心性能,因为不同的执行时间非常小。只关注代码的可读性/可维护性。是否值得优化一个简单的案例来改善几纳秒?
回答by sqlsword
In your case, since you are using an Integer
key for your HashMap
and a plain 'int
' for your switch
statement, the best performing implementation will be the switch
statement unless the number of passes through this section of code is very high (tens or hundreds of thousands).
在您的情况下,由于您为您的语句使用了一个Integer
键,HashMap
并且int
为您的switch
语句使用了一个简单的 ' ',switch
除非通过这部分代码的次数非常多(数万或数十万),否则执行最佳的实现将是语句。
回答by Cogman
The accepted answer is wrong here.
接受的答案在这里是错误的。
http://java-performance.info/string-switch-implementation/
http://java-performance.info/string-switch-implementation/
Switches will always be as fast as if not faster than hash maps. Switch statements are transformed into direct lookup tables. In the case of Integer values (ints, enums, shorts, longs) it is a direct lookup/jmp to the statement. There is no additional hashing that needs to happen. In the case of a String, it precomputes the string hash for the case statements and uses the input String's hashcode to determine where to jump. In the case of collision, it does an if/else chain. Now you might think "This is the same as HashMap, right?" But that isn't true. The hash code for the lookup is computed at compile time and it isn't reduced based on the number of elements (lower chance of collision).
开关总是和哈希映射一样快。Switch 语句被转换为直接查找表。在整数值(整数、枚举、shorts、longs)的情况下,它是对语句的直接查找/jmp。不需要进行额外的散列。在字符串的情况下,它预先计算 case 语句的字符串哈希,并使用输入字符串的哈希码来确定跳转到哪里。在发生碰撞的情况下,它会执行 if/else 链。现在你可能会想“这和 HashMap 是一样的,对吧?” 但事实并非如此。查找的哈希码是在编译时计算的,它不会根据元素的数量减少(较低的冲突机会)。
Switches have O(1) lookup, not O(n). (Ok, in truth for a small number of items, switches are turned into if/else statements. This provides better code locality and avoids additional memory lookups. However, for many items, switches are changed into the lookup table I mentioned above).
交换机有 O(1) 查找,而不是 O(n)。(好吧,事实上对于少数项目,开关变成了 if/else 语句。这提供了更好的代码局部性并避免了额外的内存查找。但是,对于许多项目,开关变成了我上面提到的查找表)。
You can read more about it here How does Java's switch work under the hood?
您可以在此处阅读有关它的更多信息 Java 的开关在幕后如何工作?
回答by John Tribe
If I have that kind of example I use Guava ImmutableMaps (sure You can use java 9 builder as well).
如果我有那种例子,我会使用 Guava ImmutableMaps(当然你也可以使用 java 9 builder)。
private static final Map<String, String> EXAMPLE = ImmutableMaps.<String, String>>builder()
.put("a", "100")
.put("b", "200")
.build();
That way they are immutable and initated only once.
这样它们是不可变的,并且只被初始化一次。
Sometimes I use strategy pattern that way:
有时我会这样使用策略模式:
private static final Map<String, Command> EXAMPLE = ImmutableMaps.<String, String>>builder()
.put("a", new SomethingCool())
.put("b", new BCool())
.build();
private static final Command DEFAULT= new DefCommand();
Use:
用:
EXAMPLE.getOrDefault("a", DEFAULT).execute(); //java 8
About performance just pick readability. You will thank me later (1 year later) :D.
关于性能只是选择可读性。以后你会感谢我(一年后):D。