为什么开关比if更快?

时间:2022-01-10 01:05:36

I have found lots of books in java saying switch statement is faster than if else statement. But I didnot find antwhere saying why switch is faster than if.

我在java中发现了很多书说switch语句比if else语句要快。但是我没有发现为什么开关比if快。

Example

I have a situation i have to choose any one item out of two i can use either of the following way

我有一个情况,我必须从两个项目中选择一个,我可以用以下任何一种方式

switch(item){

case BREAD:
     //eat Bread
break;
default:
    //leave the restaurant

}

or using if statement like the following

或者使用if语句,如下所示

if(item== BREAD){
//eat Bread
}else{
//leave the restaurant
}

considering item and BREAD is constant int value

考虑物品和面包是常量int值

In the above example which is faster in action and why?

在上面的例子中哪个动作更快,为什么?

5 个解决方案

#1


89  

Because there are special bytecodes that allow efficient switch statement evaluation when there are a lot of cases.

因为有一些特殊的字节码,在很多情况下允许有效的交换语句评估。

If implemented with IF-statements you would have a check, a jump to the next clause, a check, a jump to the next clause and so on. With switch the JVM loads the value to compare and iterates through the value table to find a match, which is faster in most cases.

如果使用If语句实现,您将进行检查、跳转到下一个子句、检查、跳转到下一个子句等等。通过switch, JVM加载要比较的值,并在value表中迭代以找到匹配,在大多数情况下,匹配速度更快。

#2


27  

A switch statement is not always faster than an if statement. It scales better than a long list of if-else statements as switch can perform a lookup based on all the values. However, for a short condition it won't be any faster and could be slower.

switch语句并不总是比if语句快。它比一长串if-else语句扩展得更好,因为switch可以基于所有的值执行查找。然而,在短期情况下,它不会更快,也可能更慢。

#3


0  

At the bytecode level, subject variable is loaded only once into processor register from a memory address in the structured .class file loaded by Runtime,and this is in a switch statement; whereas in an if-statement, a different jvm instruction is produced by your code-compiling DE, and this requires that each variable be loaded in to registers although same variable is used as in next preceeding if-statement. If you know of coding in assembly language then this would be commonplace; although java compiled coxes are not bytecode, or direct machine code, the conditional concept hereof is still consistent. Well, I tried to avoid deeper technicality upon explaining. I hope I had made the concept clear and demystified. Thank you.

在字节码级别上,subject变量只在由运行时加载的结构化.class文件中从内存地址加载到处理器寄存器中,这是在switch语句中;然而,在if-语句中,代码编译DE生成了不同的jvm指令,这要求将每个变量加载到寄存器中,尽管与后面的if-语句使用相同的变量。如果你知道汇编语言的编码,那么这将是很常见的;尽管java编译代码不是字节码,也不是直接的机器代码,但是这里的条件概念仍然是一致的。我在解释的时候尽量避免更深层次的技术性问题。我希望我已经把这个概念说清楚了。谢谢你!

#4


0  

If you are performing an insane amount of checks like 100+ you may want to consider some abstraction.

如果您正在执行大量的检查,比如100+,您可能需要考虑一些抽象。

You have incoming packets that range from ids 0 through 255. You use maybe 150 of them. You may want to consider something like the below instead of a switch of 150 ids.

有从ids 0到255的传入数据包。你可能用了150个。您可能需要考虑如下内容,而不是使用150个id。

Packets[] packets = new Packets[150];

static {
     packets[0] = new Login();
     packets[2] = new Logout();
     packets[3] = new GetMessage();
     packets[7] = new AddFriend();
     packets[9] = new JoinGroupChat(); // etc... not going to finish.
}

static final byte[] INDEX_LIST = { 
  0, 2, 3, 7, 9, // etc... Not going to do it, but this will convert packet id to index.
};

public void handlePacket(IncomingData data)
{
    int id = data.readByte();

    packets[INDEX_LIST[id]].execute(data);
}

I should also point out that index list isn't really needed and would probably slow the code down anyways. It was merely a suggestion so you don't have empty locations. Also not to mention is this situation you're only losing out of 106 indexes. I'm not 100% sure, but I believe each of these are pointing to null anyways so no real memory issues would be present.

我还应该指出,索引列表并不是真正需要的,而且无论如何可能会降低代码的速度。这只是一个建议,这样你就不会有空的位置。更不用说这种情况了,你只失去了106个指标。我不是百分之百的确定,但是我相信每一个都指向null,所以不会出现真正的内存问题。

#5


0  

The current JVM has two kinds of switch byte codes: LookupSwitch and TableSwitch.

当前JVM有两种切换字节码:LookupSwitch和汤匙witch。

Each case in a switch statement has an integer offset, if these offsets are contiguous (or mostly contiguous with no large gaps) (case 0: case 1: case 2, etc.), then TableSwitch is used.

switch语句中的每个case都有一个整型偏移量,如果这些偏移量是连续的(或者几乎是连续的,没有大的间隔)(case 0: case 1: case 2,等等),那么就使用汤匙女巫。

If the offsets are spread out with large gaps (case 0: case 400: case 93748:, etc.), then LookupSwitch is used.

如果偏移量以较大的间隔展开(情形0:情形400:情形93748:等),则使用LookupSwitch。

The difference, in short, is that TableSwitch is done in constant time because each value within the range of possible values is given a specific byte-code offset. Thus, when you give the statement an offset of 3, it knows to jump ahead 3 to find the correct branch.

简而言之,不同之处在于,它是在常数时间内完成的,因为在可能值范围内的每个值都有一个特定的字节码偏移量。因此,当您给语句一个3的偏移量时,它知道要向前跳转3以找到正确的分支。

Lookup switch uses a binary search to find the correct code branch. This runs in O(log n) time, which is still good, but not the best.

查找开关使用二进制搜索找到正确的代码分支。它在O(log n)时间内运行,仍然很好,但不是最好的。

For more information on this, see here: Difference between JVM's LookupSwitch and TableSwitch?

有关这方面的更多信息,请参见这里:JVM的LookupSwitch和汤匙witch之间的区别?

So as far as which one is fastest, use this approach: If you have 3 or more cases whose values are consecutive or nearly consecutive, always use a switch.

因此,在最快的情况下,使用这种方法:如果你有3个或更多的情况,它们的值是连续的或几乎连续的,总是使用一个开关。

If you have 2 cases, use an if statement.

如果有两种情况,使用If语句。

For any other situation, switch is most likely faster, but it's not guaranteed, since the binary-search in LookupSwitch could hit a bad scenario.

对于其他情况,switch很可能更快,但这并不能保证,因为LookupSwitch中的二进制搜索可能会遇到糟糕的情况。

Also, keep in mind that the JVM will run JIT optimizations on if statements that will try to place the hottest branch first in the code. This is called "Branch Prediction". For more information on this, see here: https://dzone.com/articles/branch-prediction-in-java

另外,请记住,JVM将对if语句执行JIT优化,如果语句试图将最热的分支放在代码的前面。这被称为“分支预测”。有关这方面的更多信息,请参见这里:https://dzone.com/articles/branch-prediction-in-java

Your experiences may vary. I don't know that the JVM doesn't run a similar optimization on LookupSwitch, but I've learned to trust the JIT optimizations and not try to outsmart the compiler.

你的经历可能会有所不同。我不知道JVM没有在LookupSwitch上运行类似的优化,但我已经学会了信任JIT优化,不要试图超越编译器。

#1


89  

Because there are special bytecodes that allow efficient switch statement evaluation when there are a lot of cases.

因为有一些特殊的字节码,在很多情况下允许有效的交换语句评估。

If implemented with IF-statements you would have a check, a jump to the next clause, a check, a jump to the next clause and so on. With switch the JVM loads the value to compare and iterates through the value table to find a match, which is faster in most cases.

如果使用If语句实现,您将进行检查、跳转到下一个子句、检查、跳转到下一个子句等等。通过switch, JVM加载要比较的值,并在value表中迭代以找到匹配,在大多数情况下,匹配速度更快。

#2


27  

A switch statement is not always faster than an if statement. It scales better than a long list of if-else statements as switch can perform a lookup based on all the values. However, for a short condition it won't be any faster and could be slower.

switch语句并不总是比if语句快。它比一长串if-else语句扩展得更好,因为switch可以基于所有的值执行查找。然而,在短期情况下,它不会更快,也可能更慢。

#3


0  

At the bytecode level, subject variable is loaded only once into processor register from a memory address in the structured .class file loaded by Runtime,and this is in a switch statement; whereas in an if-statement, a different jvm instruction is produced by your code-compiling DE, and this requires that each variable be loaded in to registers although same variable is used as in next preceeding if-statement. If you know of coding in assembly language then this would be commonplace; although java compiled coxes are not bytecode, or direct machine code, the conditional concept hereof is still consistent. Well, I tried to avoid deeper technicality upon explaining. I hope I had made the concept clear and demystified. Thank you.

在字节码级别上,subject变量只在由运行时加载的结构化.class文件中从内存地址加载到处理器寄存器中,这是在switch语句中;然而,在if-语句中,代码编译DE生成了不同的jvm指令,这要求将每个变量加载到寄存器中,尽管与后面的if-语句使用相同的变量。如果你知道汇编语言的编码,那么这将是很常见的;尽管java编译代码不是字节码,也不是直接的机器代码,但是这里的条件概念仍然是一致的。我在解释的时候尽量避免更深层次的技术性问题。我希望我已经把这个概念说清楚了。谢谢你!

#4


0  

If you are performing an insane amount of checks like 100+ you may want to consider some abstraction.

如果您正在执行大量的检查,比如100+,您可能需要考虑一些抽象。

You have incoming packets that range from ids 0 through 255. You use maybe 150 of them. You may want to consider something like the below instead of a switch of 150 ids.

有从ids 0到255的传入数据包。你可能用了150个。您可能需要考虑如下内容,而不是使用150个id。

Packets[] packets = new Packets[150];

static {
     packets[0] = new Login();
     packets[2] = new Logout();
     packets[3] = new GetMessage();
     packets[7] = new AddFriend();
     packets[9] = new JoinGroupChat(); // etc... not going to finish.
}

static final byte[] INDEX_LIST = { 
  0, 2, 3, 7, 9, // etc... Not going to do it, but this will convert packet id to index.
};

public void handlePacket(IncomingData data)
{
    int id = data.readByte();

    packets[INDEX_LIST[id]].execute(data);
}

I should also point out that index list isn't really needed and would probably slow the code down anyways. It was merely a suggestion so you don't have empty locations. Also not to mention is this situation you're only losing out of 106 indexes. I'm not 100% sure, but I believe each of these are pointing to null anyways so no real memory issues would be present.

我还应该指出,索引列表并不是真正需要的,而且无论如何可能会降低代码的速度。这只是一个建议,这样你就不会有空的位置。更不用说这种情况了,你只失去了106个指标。我不是百分之百的确定,但是我相信每一个都指向null,所以不会出现真正的内存问题。

#5


0  

The current JVM has two kinds of switch byte codes: LookupSwitch and TableSwitch.

当前JVM有两种切换字节码:LookupSwitch和汤匙witch。

Each case in a switch statement has an integer offset, if these offsets are contiguous (or mostly contiguous with no large gaps) (case 0: case 1: case 2, etc.), then TableSwitch is used.

switch语句中的每个case都有一个整型偏移量,如果这些偏移量是连续的(或者几乎是连续的,没有大的间隔)(case 0: case 1: case 2,等等),那么就使用汤匙女巫。

If the offsets are spread out with large gaps (case 0: case 400: case 93748:, etc.), then LookupSwitch is used.

如果偏移量以较大的间隔展开(情形0:情形400:情形93748:等),则使用LookupSwitch。

The difference, in short, is that TableSwitch is done in constant time because each value within the range of possible values is given a specific byte-code offset. Thus, when you give the statement an offset of 3, it knows to jump ahead 3 to find the correct branch.

简而言之,不同之处在于,它是在常数时间内完成的,因为在可能值范围内的每个值都有一个特定的字节码偏移量。因此,当您给语句一个3的偏移量时,它知道要向前跳转3以找到正确的分支。

Lookup switch uses a binary search to find the correct code branch. This runs in O(log n) time, which is still good, but not the best.

查找开关使用二进制搜索找到正确的代码分支。它在O(log n)时间内运行,仍然很好,但不是最好的。

For more information on this, see here: Difference between JVM's LookupSwitch and TableSwitch?

有关这方面的更多信息,请参见这里:JVM的LookupSwitch和汤匙witch之间的区别?

So as far as which one is fastest, use this approach: If you have 3 or more cases whose values are consecutive or nearly consecutive, always use a switch.

因此,在最快的情况下,使用这种方法:如果你有3个或更多的情况,它们的值是连续的或几乎连续的,总是使用一个开关。

If you have 2 cases, use an if statement.

如果有两种情况,使用If语句。

For any other situation, switch is most likely faster, but it's not guaranteed, since the binary-search in LookupSwitch could hit a bad scenario.

对于其他情况,switch很可能更快,但这并不能保证,因为LookupSwitch中的二进制搜索可能会遇到糟糕的情况。

Also, keep in mind that the JVM will run JIT optimizations on if statements that will try to place the hottest branch first in the code. This is called "Branch Prediction". For more information on this, see here: https://dzone.com/articles/branch-prediction-in-java

另外,请记住,JVM将对if语句执行JIT优化,如果语句试图将最热的分支放在代码的前面。这被称为“分支预测”。有关这方面的更多信息,请参见这里:https://dzone.com/articles/branch-prediction-in-java

Your experiences may vary. I don't know that the JVM doesn't run a similar optimization on LookupSwitch, but I've learned to trust the JIT optimizations and not try to outsmart the compiler.

你的经历可能会有所不同。我不知道JVM没有在LookupSwitch上运行类似的优化,但我已经学会了信任JIT优化,不要试图超越编译器。