Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Is if fast or switch fast in java?

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "if fast or switch fast in java". The explanation in the article is simple and clear, easy to learn and understand. Please follow the editor's train of thought to study and learn "if fast or switch fast in java".

Switch VS if

Try to use switch because its performance is relatively high, but how much higher is it? And why it is high will be revealed for you in this article.

We still use the JMH (Java Microbenchmark Harness,JAVA Microbenchmark Suite) framework provided by Oracle to test. First, we introduce the JMH framework and add the following configuration to the pom.xml file:

Org.openjdk.jmh jmh-core 1.23

Then write the test code, and we add five conditional judgment branches here. The specific implementation code is as follows:

Import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit @ BenchmarkMode (Mode.AverageTime) / / Test completion time @ OutputTimeUnit (TimeUnit.NANOSECONDS) @ Warmup (iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS) / / 2 rounds of preheating, 1 s @ Measurement (iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) / / 5 rounds of test Each time 3s @ Fork (1) / / fork 1 thread @ State (Scope.Thread) / / one instance public class SwitchOptimizeTest {static Integer _ NUM = 9 per test thread Public static void main (String [] args) throws RunnerException {/ / start the benchmark Options opt = new OptionsBuilder () .include (SwitchOptimizeTest.class.getSimpleName ()) / the test class to be imported .output ("/ Users/admin/Desktop/jmh-switch.log") / / the file .build () that outputs the test results New Runner (opt) .run (); / / execute the test} @ Benchmark public void switchTest () {int num1; switch (_ NUM) {case 1: num1 = 1; break; case 3: num1 = 3; break Case 5: num1 = 5; break; case 7: num1 = 7; break; case 9: num1 = 9; break; default: num1 =-1 Break;}} @ Benchmark public void ifTest () {int num1; if (_ NUM = = 1) {num1 = 1;} else if (_ NUM = = 3) {num1 = 3;} else if (_ NUM = = 5) {num1 = 5 } else if (_ NUM = = 7) {num1 = 7;} else if (_ NUM = = 9) {num1 = 9;} else {num1 =-1;}

The test results of the above code are as follows:

Note: the test environment of this article is: JDK 1.8 / Mac mini (2018) / Idea 2020.1

As can be seen from the above results (Score column), the average execution completion time of switch is about 2.33 times faster than that of if.

Performance analysis.

Why is the performance of switch much higher than that of if?

We need to start with their bytecode, and we use their code to generate bytecode using javac as follows:

Public class com.example.optimize.SwitchOptimize {static java.lang.Integer _ NUM; public com.example.optimize.SwitchOptimize (); Code: 0: aload_0 1: invokespecial # 1 / / Method java/lang/Object. "": () V 4: return public static void main (java.lang.String []) Code: 0: invokestatic # 7 / / Method switchTest: () V 3: invokestatic # 12 / / Method ifTest: () V 6: return public static void switchTest (); Code: 0: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 3: invokevirtual # 19 / / Method java/lang/Integer.intValue: () I 6: tableswitch {/ / 1 to 9 1: 56 2: 83 3: 61 4: 83 5: 66 6: 83 7: 71 8: 83 9: 77 default: 83} 56: iconst_1 57: istore_0 58: goto 85 61: iconst_3 62: istore_0 63: goto 85 66: iconst_5 67: istore_0 68: goto 85 71: bipush 7 73: istore_0 74: goto 85 77: bipush 9 79: istore_0 80: goto 85 83: iconst_m1 84: istore_0 85: return public static void ifTest () Code: 0: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 3: invokevirtual # 19 / / Method java/lang/Integer.intValue: () I 6: iconst_1 7: if_icmpne 15 10: iconst_1 11: istore_0 12: goto 81 15: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 18: invokevirtual # 19 / / Method java/lang/Integer.intValue: () I 21: iconst_3 22: if_icmpne 30 25: iconst_3 26: istore_0 27: goto 81 30: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 33: invokevirtual # 19 / / Method java/lang/Integer.intValue: () I 36: iconst_5 37: if_icmpne 45 40: iconst_5 41: istore_0 42: goto 81 45: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 48: invokevirtual # 19 / Method java/lang/Integer.intValue: () I 51: bipush 7 53: if_icmpne 62 56: bipush 7 58: istore_0 59: goto 81 62: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 65: invokevirtual # 19 / / Method java/lang/Integer.intValue: () I 68: bipush 9 70: if_icmpne 79 73: bipush 9 75: istore_0 76: goto 81 79: iconst_m1 80: istore_0 81: return static {} Code: 0: iconst_1 1: invokestatic # 25 / / Method java/lang/Integer.valueOf: (I) Ljava/lang/Integer; 4: putstatic # 15 / / Field _ NUM:Ljava/lang/Integer; 7: return}

The most important information in these bytecodes is "getstatic # 15", which indicates that the "_ NUM" variable and condition are taken out for judgment.

As you can see from the bytecode above, variables and conditions are compared only once in switch, while variables and conditions are compared each time in if, so if is much slower than switch.

Increase the amount of test

In the previous test code, we used five branching conditions to test the performance of if and switch, so what would happen if the branch criteria were tripled (15)?

The implementation code for 15 branch judgments is as follows:

Package com.example.optimize; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit @ BenchmarkMode (Mode.AverageTime) / / Test completion time @ OutputTimeUnit (TimeUnit.NANOSECONDS) @ Warmup (iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS) / / 2 rounds of preheating, 1 s @ Measurement (iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) / / 5 rounds of test Each time 3s @ Fork (1) / / fork 1 thread @ State (Scope.Thread) / / one instance public class SwitchOptimizeTest {static Integer _ NUM = 1 per test thread Public static void main (String [] args) throws RunnerException {/ / start the benchmark Options opt = new OptionsBuilder () .include (SwitchOptimizeTest.class.getSimpleName ()) / the test class to be imported .output ("/ Users/admin/Desktop/jmh-switch.log") / / the file .build () that outputs the test results New Runner (opt) .run (); / / execute the test} @ Benchmark public void switchTest () {int num1; switch (_ NUM) {case 1: num1 = 1; break; case 2: num1 = 2; break Case 3: num1 = 3; break; case 4: num1 = 4; break; case 5: num1 = 5; break; case 6: num1 = 6 Break; case 7: num1 = 7; break; case 8: num1 = 8; break; case 9: num1 = 9; break Case 10: num1 = 10; break; case 11: num1 = 11; break; case 12: num1 = 12; break; case 13: num1 = 13 Break; case 14: num1 = 14; break; case 15: num1 = 15; break; default: num1 =-1; break } @ Benchmark public void ifTest () {int num1; if (_ NUM = = 1) {num1 = 1;} else if (_ NUM = = 2) {num1 = 2;} else if (_ NUM = = 3) {num1 = 3 } else if (_ NUM = = 4) {num1 = 4;} else if (_ NUM = = 5) {num1 = 5;} else if (_ NUM = = 6) {num1 = 6;} else if (_ NUM = = 7) {num1 = 7 } else if (_ NUM = = 8) {num1 = 8;} else if (_ NUM = = 9) {num1 = 9;} else if (_ NUM = = 10) {num1 = 10;} else if (_ NUM = = 11) {num1 = 11 } else if (_ NUM = = 12) {num1 = 12;} else if (_ NUM = = 13) {num1 = 13;} else if (_ NUM = = 14) {num1 = 14;} else if (_ NUM = = 15) {num1 = 15;} else {num1 =-1 }}}

The test results of the above code are as follows:

As can be seen from the value of Score, when the number of branches is increased to 15, the performance of switch is about 3.7 times higher than that of if, while the test results of the previous five branches show that the performance of switch is about 2.3 times higher than that of if, that is to say, the more branch judgment conditions, the more obvious the characteristics of high performance of switch.

Switch's Secret

For switch, the bytecode he finally generates has two forms, one is tableswitch, and the other is lookupswitch. The decision on which form to use in the final generated code depends on whether the addition of switch is compact. For example, when case is 1. 2. 3. 4, tableswitch is used. For non-compact conditions such as case is 1. 33. 55. 22, lookupswitch is used, and the test code is as follows:

Public class SwitchOptimize {static Integer _ NUM = 1; public static void main (String [] args) {tableSwitchTest (); lookupSwitchTest ();} public static void tableSwitchTest () {int num1; switch (_ NUM) {case 1: num1 = 1; break Case 2: num1 = 2; break; case 3: num1 = 3; break; case 4: num1 = 4; break; case 5: num1 = 5 Break; case 6: num1 = 6; break; case 7: num1 = 7; break; case 8: num1 = 8; break Case 9: num1 = 9; break; default: num1 =-1; break;}} public static void lookupSwitchTest () {int num1; switch (_ NUM) {case 1: num1 = 1 Break; case 11: num1 = 2; break; case 3: num1 = 3; break; case 4: num1 = 4; break Case 19: num1 = 5; break; case 6: num1 = 6; break; case 33: num1 = 7; break; case 8: num1 = 8 Break; case 999: num1 = 9; break; default: num1 =-1; break;}

The corresponding bytecode is as follows:

Public class com.example.optimize.SwitchOptimize {static java.lang.Integer _ NUM; public com.example.optimize.SwitchOptimize (); Code: 0: aload_0 1: invokespecial # 1 / / Method java/lang/Object. "": () V 4: return public static void main (java.lang.String []) Code: 0: invokestatic # 7 / / Method tableSwitchTest: () V 3: invokestatic # 12 / / Method lookupSwitchTest: () V 6: return public static void tableSwitchTest (); Code: 0: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 3: invokevirtual # 19 / / Method java/lang/Integer.intValue: () I 6: tableswitch {/ / 1 to 9 1: 56 2: 61 3: 66 4: 71 5: 76 6: 81 7: 87 8: 93 9: 99 default: 105} 56: iconst_1 57: istore_0 58: goto 107 61: iconst_2 62: istore_0 63: goto 107 66: iconst_3 67: istore_0 68: goto 107 71: iconst_4 72: istore_0 73: goto 107 76: iconst_5 77: istore_0 78: goto 107 81: bipush 6 83: istore_0 84: goto 107 87: Bipush 7 89: istore_0 90: goto 10793: bipush 8 95: istore_0 96: goto 10799: bipush 9 101101: istore_0 102105: goto 107105: iconst_m1 106: istore_0 107: return public static void lookupSwitchTest () Code: 0: getstatic # 15 / / Field _ NUM:Ljava/lang/Integer 3: invokevirtual # 19 / / Method java/lang/Integer.intValue: () I 6: lookupswitch {/ / 9 1: 88 3: 98 4: 103 6: 113 8: 125 11: 93 19: 108 33: 119 999: 131 default: 137} 88: iconst_1 89: istore_0 90: goto 139 93: iconst_2 94: istore_0 95: goto 139 98: iconst_3 99: istore_0 100: goto 139 103: iconst_4 104: istore_0 105: goto 139 108: iconst_5 109: istore_0 110: goto 139 113: bipush 6 115: istore_0 116: goto 139 119: bipush 7 121: istore_0 122: goto 139 125: bipush 8 127: istore_0 128: goto 139 131: bipush 9 133: istore_0 134: goto 139 137: iconst_m1 138: istore_0 139: return static {} Code: 0: iconst_1 1: invokestatic # 25 / / Method java/lang/Integer.valueOf: (I) Ljava/lang/Integer; 4: putstatic # 15 / / Field _ NUM:Ljava/lang/Integer; 7: return}

From the bytecode above, you can see the tableswitch used by tableSwitchTest, while lookupSwitchTest is the lookupswitch used.

Tableswitch VS lookupSwitchTest

When a tableswitch is executed, the int value at the top of the stack is directly used as an index in the table to grab the jump target and perform the jump immediately. In other words, the storage structure of tableswitch is similar to an array, and the elements are retrieved directly by index, so the time complexity of the whole query is O (1), which means that its search speed is very fast.

When executing lookupswitch, branch-by-branch comparisons are performed or queries are made using dichotomy, so the query time complexity is O (log n), so using lookupswitch is slower than tableswitch.

Next, let's use the actual code to test the performance between the two of them. the test code is as follows:

Package com.example.optimize; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit @ BenchmarkMode (Mode.AverageTime) / / Test completion time @ OutputTimeUnit (TimeUnit.NANOSECONDS) @ Warmup (iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS) / / 2 rounds of preheating, 1 s @ Measurement (iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) / / 5 rounds of test Each time 3s @ Fork (1) / / fork 1 thread @ State (Scope.Thread) / / one instance public class SwitchOptimizeTest {static Integer _ NUM =-1 per test thread Public static void main (String [] args) throws RunnerException {/ / start the benchmark Options opt = new OptionsBuilder () .include (SwitchOptimizeTest.class.getSimpleName ()) / / the test class to be imported. Build (); new Runner (opt). Run () / / execute the test} @ Benchmark public void tableSwitchTest () {int num1; switch (_ NUM) {case 1: num1 = 1; break; case 2: num1 = 2; break Case 3: num1 = 3; break; case 4: num1 = 4; break; case 5: num1 = 5; break; case 6: num1 = 6 Break; case 7: num1 = 7; break; case 8: num1 = 8; break; case 9: num1 = 9; break Default: num1 =-1; break;}} @ Benchmark public void lookupSwitchTest () {int num1; switch (_ NUM) {case 1: num1 = 1; break Case 11: num1 = 2; break; case 3: num1 = 3; break; case 4: num1 = 4; break; case 19: num1 = 5 Break; case 6: num1 = 6; break; case 33: num1 = 7; break; case 8: num1 = 8; break Case 999: num1 = 9; break; default: num1 =-1; break;}

The test results of the above code are as follows:

It can be seen that the performance of tableswitch is about 1.3 times faster than that of lookupwitch when the number of branches is 9. But even so, lookupwitch still performs much better than if queries.

Thank you for reading, the above is the content of "if fast or switch fast in java". After the study of this article, I believe you have a deeper understanding of the question of if fast or switch fast in java, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report