Lots of Java books describe the switch statement as being faster than the if else statement. But I did not find out anywhere why switch is faster than if.
Example
I have a situation I have to choose any one item out of two. I can use either use
switch (item) {
case BREAD:
//eat Bread
break;
default:
//leave the restaurant
}
or
if (item == BREAD) {
//eat Bread
} else {
//leave the restaurant
}
considering item and BREAD is a constant int value.
In the above example which is faster in action and why?
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.
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.
The current JVM has two kinds of switch byte codes: LookupSwitch and TableSwitch.
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.
If the offsets are spread out with large gaps (case 0: case 400: case 93748:, etc.), then LookupSwitch is used.
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.
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.
For more information on this, see here: Difference between JVM's LookupSwitch and TableSwitch?
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.
If you have 2 cases, use an if statement.
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.
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
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.
So if you plan to have loads of packets memory isn't really a large cost these days and arrays are pretty fast. You also cannot rely on a switch statement to auto generate a jump table and as such it's easier to generate the jump table scenario yourself. As you can see in below example we assume a maximum of 255
packets.
To get the below result your need abstraction.. i'm not going to explain how that works so hopefully you have an understanding of that.
I updated this to set the packet size to 255 if you need more then that you'll have to do a bounds check for (id < 0) || (id > length).
Packets[] packets = new Packets[255];
static {
packets[0] = new Login(6);
packets[2] = new Logout(8);
packets[4] = new GetMessage(1);
packets[8] = new AddFriend(0);
packets[11] = new JoinGroupChat(7); // etc... not going to finish.
}
public void handlePacket(IncomingData data)
{
int id = data.readByte() & 0xFF; //Secure value to 0-255.
if (packet[id] == null)
return; //Leave if packet is unhandled.
packets[id].execute(data);
}
Edit since I use a Jump Table in C++ a lot now i'll show an example of a function pointer jump table. This is a very generic example, but I did run it and it works correctly. Keep in mind you must set the pointer to NULL, C++ will not do this automatically like in Java.
#include <iostream>
struct Packet
{
void(*execute)() = NULL;
};
Packet incoming_packet[255];
uint8_t test_value = 0;
void A()
{
std::cout << "I'm the 1st test.\n";
}
void B()
{
std::cout << "I'm the 2nd test.\n";
}
void Empty()
{
}
void Update()
{
if (incoming_packet[test_value].execute == NULL)
return;
incoming_packet[test_value].execute();
}
void InitializePackets()
{
incoming_packet[0].execute = A;
incoming_packet[2].execute = B;
incoming_packet[6].execute = A;
incoming_packet[9].execute = Empty;
}
int main()
{
InitializePackets();
for (int i = 0; i < 512; ++i)
{
Update();
++test_value;
}
system("pause");
return 0;
}
Also another point i'd like to bring up is the famous Divide and Conquer. So my above 255 array idea could be reduced to no more then 8 if statements as a worst case scenario.
I.e. but keep in mind it get's messy and hard to manage fast and my other approach is generally better, but this is utilize in cases where arrays just won't cut it. You have to figure out your use case and when each situation works best. Just as you wouldn't want to use either of these approaches if you only have a few checks.
If (Value >= 128)
{
if (Value >= 192)
{
if (Value >= 224)
{
if (Value >= 240)
{
if (Value >= 248)
{
if (Value >= 252)
{
if (Value >= 254)
{
if (value == 255)
{
} else {
}
}
}
}
}
}
}
}
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.
Related
On Stackoverflow I found the following String-Equal-Function, which should be resistent against timing attacks.
private boolean equalSignatureString(String signature1, String signature2) {
if(signature1.length() != signature2.length()) {
return false;
}
byte[] signature1Byte = signature1.getBytes();
byte[] signature2Byte = signature2.getBytes();
int result = 0;
for(int i = 0; i < signature1Byte.length; i++) {
result |= signature1Byte[i] ^ signature2Byte[i];
}
return result == 0;
}
I wonder why this is save against timing-attacks. I understand, that we compare the complete length of the strings even if they doesn't match after the first char (which could be a point for timing attacks). But if signature1Byte[i] is not equal to signature2Byte[i] then we have to add +1 to result otherwise not. Doesn't the "add +1" takes also longer than "just proceed to the next loop"? Wouldn't it be better to count up an other variable (which is useless) when the bytes are equal, so we always have the same running time?
While we you could possible do that, implementation which use if not only slower, but may have unpredictable problem because of optimization.
JIT may throw away your unused variable and CPU branch prediction may also influence on how long each branch is executed.
This probably applies to more than C and Java, of course, but those are the two languages I am more familiar with, so let us take this simple example:
int foo(int arg)
{
if (arg > 0)
return 1;
return 0;
}
Now, I have seen two interpretations as far as return is concerned:
this is a "different code path" since it exits the method; as such any return statement should increase the complexity by 1. In this case, the sample code above has a complexity of 3; or
return just exits the method, no reason to count it in. In this case, the sample code above has a complexity of 1.
Is any interpretation above the "correct", canonical one as far as cyclomatic complexity is concerned? I tend to favor the latter case but I'm no CS theorist...
That code has two distinct paths through the function: one that corresponds to arg > 0 being true and the other corresponding to it being false.
The number of return statements involved does not affect that, since it does not change the number of distinct paths through the function. Your code could be rewritten as
int foo(int arg)
{
int retval = 0;
if (arg > 0) retval = 1;
return retval;
}
which has exactly the same number of paths, despite having one less return statement.
Your cyclomatic complexity would be 2, here's why:
Your code is essentially this:
int foo(int arg)
{
int out;
if (arg > 0)
out = 1;
else
out = 0;
return out;
}
plain return statement dont count toward complexity. You only have 1 if statement, no if else statements. Hence, your cyclomatic complexity will be 2, as there is 1 alternate path to the main path.
If return statements would count, your cyclomatic complexity of the same method could be 3 OR 4 (see my code vs yours), this should make clear why return statements aren't included.
Let's say that I have two strings that can be passed as parameter:
String one = "one";
String two = "two";
Which of the following methods would be the most efficiƫnt?
private void exampleOne(String example){
if(example.equals("one"){
// do this
}else{
// do this
}
}
private void exampleTwo(String example){
if(example.equals("one"){
//do this
}else if(example.equals("two"){
// do this
}
}
private void exampleThree(String example){
if(example.equals("one"){
// do this
}
if(example.equals("two"){
// do this
}
}
I would compare the methods for efficiency, if they have the same functionality. Currently, all the 3 methods are functionally different. So, no point is there in comparing them.
exampleOne() - If example is equal to "one", execute if. Execute else for all other values.
exampleTwo() - If example is equal to "one", execute if. Execute else if, if it is equal to "two", else for all other values, do nothing - (Here's one difference).
exampleThree() - Well, this one (as it stands) is more or less same as the 1st one, with one extra comparison, which btw, isn't going to affect much as far as efficiency is concerned. However, there are chances that both the if statements might execute in this method, if in between the two if statements, you assign string "two" to example, which is not possible in exampleOne method. To be more clear, you have two independent if blocks here, while in the first method, it's an if-else block (only one of which will be executed).
The one that, statistically speaking, makes the fewest string compares i.e.
if (example.equals("one"){
// do this
} else {
// do this
}
No one is the most efficient due that you have just two options, you should consider that the value doesn't be not one and not two, maybe other one (empty? null?) SO you should write something like that:
if(example.equals("one"){
//do this 1
}else if(example.equals("two"){
// do this 2
}else{
// do this 3
}
Those blocs can not be compared ans you can not state what is the best of them as they flow is different for each case.
This bloc provide two paths a positive and not.
private void exampleOne(String example){
if("one".equals(example){ //deciosn
// path positive
}else{
// path negative
}
}
This block provide three paths, positive, negative-positive, negative-negative
private void exampleTwo(String example){
if("one".equals(example){
//path positive
}else {
// path negative
if("two".equals(example{
// path negative-positive
}
}
}
This block provide four path, postive, negative and positive negative.
private void exampleThree(String example){
if("pne".equals(example){
// path positive
}
if("two".equals(example){
// path positive
}
}
As you see you have four different piece of code that you should not compare to state what is more efficient.
You should focus on the algorithm behind instead not how do the look.
Tip:
Try to use constant on the left side of compare, so you would avoid problems like dereferences and invalid assign.
I would say the first one, just because it only has to evaluate one expression every time...
In my opinion the second one because there you have direct control on both scenarios. When Sring is "one" and "two".
In exampleOne, the method doens't care if "two" or "three" is passed. It cares only situation if "one" is passed
The first one. Because you don't have to check other condition. In other you to make more operation.
The most efficient: 1, 2, 3.
But If you will have to check if i==0 and you will expect that most of them will be != better write if (i != 0) {} else{} than If (i==0) {...}
Keep everything as simple as possible
I'd say first, because if it just says else with no condition then it won't have to check anything, just go straight into 'else'
Theoretically, the first is most efficient.
Practically, you should go for the second, as it offers better readability and maintainability.
Remember, premature optimization is the root of all evil :)
1) most efficient, but this isn't good for maintainability.
private void exampleOne(String example){
if(example.equals("one"){
// do this
}else{
// do this
}
}
2) second efficient, but it is good for maintainability.
private void exampleTwo(String example){
if(example.equals("one"){
//do this
}else if(example.equals("two"){
// do this
}
}
3) third efficient.
private void exampleThree(String example){
if(example.equals("one"){
// do this
}
if(example.equals("two"){
// do this
}
}
i dont know what are your needs so, here you have mi opinions,
the first one, will ALLWAYS do only one checking.. so in that particular example it will be the one with less COMPARISONS.
the second ONE, will do at worst 2 comparisons 1 for "one" and 1 for "two" but... (there is allways a but) it will not any any job if the string is lets say "three" (in the first example it will go to the else)
the 3 example will do ALWAYS 2 COMPARISONS un less you put returns inside the ifs.
so, my opinion is there is not enough information to say wich one is more optimal.
one adition: you can try, instead of writing endles if... to use a case like this one:
switch (true) {
case example.equals("one"):
break;
case example.equals("two"):
break;
default:
break;
}
Apparently the first method would be the most efficient one compared with the possible values of parameters , since the additional if condition in the other methods is useless and will have nothing to do in your case. (extra condition check ==> lower efficiency)
I am writing a method, and would like to know if the attached code is efficient depending on how it is written:
public boolean isThreeOfKind(PlayingCard[] hand)
{
// if(hand[0].getRank() == hand[2].getRank())
// return true;
// else if(hand[1].getRank() == hand[3].getRank())
// return true;
// else if(hand[2].getRank() == hand[4].getRank())
// return true;
return (hand[0].getRank() == hand[2].getRank() ||
hand[1].getRank() == hand[3].getRank() ||
hand[2].getRank() == hand[4].getRank());
}
So as you can see I have an if else if statement commented out, and a return statement doing the same thing basically, which would be more efficient and according to coding standards?
No difference in efficiency, but definite difference in style, the second one being much better. However, this particular logic is really just
for (int i = 0; i < 3; i++)
if (hand[i].getRank() == hand[i+2].getRank()) return true;
return false;
This type of question might be better on CodeReview because it's more of an opinion. But In my opinion it's much easier to read the non-commented portion and performance shouldn't be worried about until it becomes an issue (especially in something like this). For more on that see the Program optimization article on Wikipedia particularly the When to Optimize section.
As Jeffery said, I'd say readability is more valuable than efficiency in this case (I wouldn't say that's a universal rule).
You might be interested in a concept called Short-Circuit Evaluation. Notice that || is a short-circuit operator in Java. As such, you'll get the same effect as the if statements if the first statement is true (the other two will not be evaluated).
That being said, I'm not sure if those two bits of code compile down into the same function (they might depending on the compiler implementation). If they do not compile down the same, the second will likely be faster.
Or if you prefer only one exit point in the method and array boundary checking:
boolean found = false;
for (int i = 0; !found && i < hand.length - 2; i++)
found = (hand[i].getRank() == hand[i + 2].getRank());
return found;
I have an if statement with many conditions (have to check for 10 or 15 constants to see if any of them are present.)
Instead of writing something like:
if (x == 12 || x == 16 || x == 19 || ...)
is there any way to format it like
if x is [12, 16, 19]?
Just wondering if there is an easier way to code this, any help appreciated.
The answers have been very helpful, but I was asked to add more detail by a few people, so I will do that to satiate their curiosity. I was making a date validation class that needed to make sure days were not > 30 in the months that have only 30 days (of which there are 4, I think) and I was writing an if statement to check things like this:
if (day > 30 && (month == 4 || month == 6 || month == 9 || month == 11))
I was just wondering if there was a faster way to code things like that - many of the answers below have helped.
I use this kind of pattern often. It's very compact:
Define a constant in your class:
private static final Set<Integer> VALUES = Set.of(12, 16, 19);
// Pre Java 9 use: VALUES = new HashSet<Integer>(Arrays.asList(12, 16, 19));
In your method:
if (VALUES.contains(x)) {
...
}
Set.of() returns a HashSet, which performs very well even for very large sets.
If performance is not important, you can code the gist of it into one line for less code footprint:
if (Set.of(12, 16, 19).contains(x))
but know that it will create a new Set every time it executes.
Do you want to switch to this??
switch(x) {
case 12:
case 16:
case 19:
//Do something
break;
default:
//Do nothing or something else..
break;
}
If the set of possibilities is "compact" (i.e. largest-value - smallest-value is, say, less than 200) you might consider a lookup table. This would be especially useful if you had a structure like
if (x == 12 || x == 16 || x == 19 || ...)
else if (x==34 || x == 55 || ...)
else if (...)
Set up an array with values identifying the branch to be taken (1, 2, 3 in the example above) and then your tests become
switch(dispatchTable[x])
{
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
}
Whether or not this is appropriate depends on the semantics of the problem.
If an array isn't appropriate, you could use a Map<Integer,Integer>, or if you just want to test membership for a single statement, a Set<Integer> would do. That's a lot of firepower for a simple if statement, however, so without more context it's kind of hard to guide you in the right direction.
Use a collection of some sort - this will make the code more readable and hide away all those constants. A simple way would be with a list:
// Declared with constants
private static List<Integer> myConstants = new ArrayList<Integer>(){{
add(12);
add(16);
add(19);
}};
// Wherever you are checking for presence of the constant
if(myConstants.contains(x)){
// ETC
}
As Bohemian points out the list of constants can be static so it's accessible in more than one place.
For anyone interested, the list in my example is using double brace initialization. Since I ran into it recently I've found it nice for writing quick & dirty list initializations.
You could look for the presence of a map key or see if it's in a set.
Depending on what you're actually doing, though, you might be trying to solve the problem wrong :)
No you cannot do that in Java. you can however write a method as follows:
boolean isContains(int i, int ... numbers) {
// code to check if i is one of the numbers
for (int n : numbers) {
if (i == n) return true;
}
return false;
}
With Java 8, you could use a primitive stream:
if (IntStream.of(12, 16, 19).anyMatch(i -> i == x))
but this may have a slight overhead (or not), depending on the number of comparisons.
Here is another answer based on a comment above, but simpler:
List numbers= Arrays.asList(1,2,3,4,5);
if(numbers.contains(x)){
//
}