Are there situations where if statements are irreplaceable by jump tables? - java

I did not went too deep into this idea, but i wonder if if statements can be replaced by jump tables.
If we have a set of ifs like
if(x = 0)
{
...
}
if(x = 1)
{
...
}
if(x = 2)
{
...
}
We could simply jump, direcly, to the routine that pertains to the value of x, if we had a table with pointers for each routine.
In other situations like user input, let's assume we read a character from stdin, we
would have like
if(c = 'a')
{
...
}
if(c = 'b')
{
...
}
We could also find a way to índex a jump table based on the value of c
My question is, in which situations is it TOTALLY impossible to replace an if by a jump table? Can computation be performed without if statements (or equivalents)

Jump tables are limited to situations when you check equality. They are less appropriate when you need to use non-equality checks, and also for if statements with OR conditions.
Of course you could always use a degenerate jump table on a single boolean condition, like this:
boolean condition = a > b && c < d || e != f;
switch (condition) {
case true: ... break;
case false: ... break;
}
However, this does not offer any advantage over a straightforward conditional.

Related

How can i simplify this if sequence?

I am learning java, and i got stuck in a stupid situation.
I could just throw all my code in here, but it would only confuse you even more. So I converted my logical thinking into this:
if (a)
{
*instruction 1*
}
if (!a && b && !c)
{
*instruction 2*
}
if (!a && b && c)
{
*instruction 3*
}
else
{
*instruction 4*
}
All I want to know is if i can simplify this, so i don't use so many "if" statements...
And I'd like to know how you came to your conclusion.
Thanks in advance! (Yes, I'm dumb, help me)
EDIT:
I'm adding a truth-table with every combination of a, b and c:
If a, b and c are local variables or otherwise guaranteed not to change while you go through the if-statements, then you can write your code as:
if (a) {
// instruction 1
} else if (b) {
if (!c) {
// instruction 2
} else {
// instruction 3
}
}
if (a || !b || !c) {
// instruction 4
}
However, it is still pretty complex. Depending on the meaning of a, b and c and how you calculate them, you should probably refactor this code into multiple methods. For example, the if-statement relating to c might fit well into a single-responsibility method.
If you want to verify whether this change is correct, you can create a truth-table with all possible combinations of a, b and c being true or false. You would check which instruction would be performed in your first code, and which instruction gets performed in the new code.
You probably want to use a switch statement to make this more readable.
Something like:
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
The switch statement is a multi-way branch statement. It provides an easy way to dispatch execution to different parts of code based on the value of the expression. Basically, the expression can be byte, short, char, and int primitive data types. Beginning with JDK7, it also works with enumerated types ( Enums in java), the String class and Wrapper classes.
As far as i can see there's a Wrapper Class for Booleans.
boolean result = switch (ternaryBool) {
case TRUE -> true;
case FALSE -> false;
case FILE_NOT_FOUND -> throw new UncheckedIOException(
"This is ridiculous!",
new FileNotFoundException());
// as we'll see in "Exhaustiveness", `default` is not necessary
default -> throw new IllegalArgumentException("Seriously?! 🤬");
};
https://blog.codefx.org/java/switch-expressions/
In multiple conditions, I would use the switch statement to make it easier to read.
https://beginnersbook.com/2017/08/java-switch-case/

can you have two conditions in an if statement

I'm a beginner in coding. I was recently working with to create a chatting programme where a user will chat with my computer. Here is a part of the code:
System.out.println("Hello, what's our name? My name is " + answer4);
String a = scanner1.nextLine();
System.out.println("Ok, Hello, " + a + ", how was your day, good or bad?");
String b = scanner2.nextLine();
**if (b.equals("good"))** { //1
System.out.println("Thank goodness");
} else **if (b.equals("it was good"))** { //2
System.out.println("Thank goodness");
} else **if (b.equals("bad"))** { //3
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
} else **if (b.equals("it was bad"))**{ //4
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
}
if(age<18){System.out.println("How was school?");}
else if (age>=18){System.out.println("How was work?");}
The conditions of the if statements are in Bold (surrounded with **). In case of first and the second condition I want my application to do same thing. Similarly third and fourth condition. I thought it was possible to somehow group them in if statement.
I tried with below code but it doesn't compile:
if (b.equals("good"), b.equals("it was good")) {
System.out.println("Thank goodness");
} else if (b.equals("bad"),(b.equals("it was bad"))) {
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
}
Can someone correct it for me?
You can use logical operators to combine your boolean expressions.
&& is a logical and (both conditions need to be true)
|| is a logical or (at least one condition needs to be true)
^ is a xor (exactly one condition needs to be true)
(== compares objects by identity)
For example:
if (firstCondition && (secondCondition || thirdCondition)) {
...
}
There are also bitwise operators:
& is a bitwise and
| is a bitwise or
^ is a xor
They are mainly used when operating with bits and bytes. However there is another difference, let's take again a look at this expression:
firstCondition && (secondCondition || thirdCondition)
If you use the logical operators and firstCondition evaluates to false then Java will not compute the second or third condition as the result of the whole logical expression is already known to be false. However if you use the bitwise operators then Java will not stop and continue computing everything:
firstCondition & (secondCondition | thirdCondition)
Here are some common symbols used in everyday language and their programming analogues:
"," usually refers to "and" in everyday language. Thus, this would translate to the AND operator, &&, in Java.
"/" usually refers to "or" in everyday language. Thus, this would translate to the OR operator, ||, in Java.
"XOR" is simply "x || y but both cannot be true at the same time". This translates to x ^ y in Java.
In your code, you probably meant to use "or" (you just used the incorrect "incorrect solution" :p), so you should use "||" in the second code block for it to become identical to the first code block.
Hope this helped :)
You're looking for the "OR" operator - which is normally represented by a double pipe: ||
if (b.equals("good") || b.equals("it was good")) {
System.out.println("Thank goodness");
} else if (b.equals("bad") || b.equals("it was bad")) {
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
}
This is probably more answer than you need at this point. But, as several others already point out, you need the OR operator "||". There are a couple of points that nobody else has mentioned:
1) If (b.equals("good") || b.equals("it was good")) <-- If "b" is null here, you'll get a null pointer exception (NPE). If you are genuinely looking at hard-coded values, like you are here, then you can reverse the comparison. E.g.
if ("good".equals(b) || "it was good".equals(b))
The advantage of doing it this way is that the logic is precisely the same, but you'll never get an NPE, and the logic will work just how you expect.
2) Java uses "short-circuit" testing. Which in lay-terms means that Java stops testing conditions once it's sure of the result, even if all the conditions have not yet been tested. E.g.:
if((b != null) && (b.equals("good") || b.equals("it was good")))
You will not get an NPE in the code above because of short-circuit nature. If "b" is null, Java can be assured that no matter what the results of the next conditions, the answer will always be false. So it doesn't bother performing those tests.
Again, that's probably more information than you're prepared to deal with at this stage, but at some point in the near future the NPE of your test will bite you. :)
You can have two conditions if you use the double bars(||). They mean "Or". That means only ONE of your conditions has to be true for the loop to execute.
Something like this:
if(condition || otherCondition || anotherCondition) {
//code here
If you want all of conditions to be true use &&. This means that ALL conditions must be true in order for the loop to execute. if any one of them is false the loop will not execute.
Something like this:
if(condition && otherCondition && anotherCondition) {
//code here
You can also group conditions, if you want certain pairs of them to be true. something like:
if(condition || (otherCondition && anotherCondition)) {
//code here
There is a simpler way.
if (b.contains("good")) {
...
}
else if (b.contains("bad")) {
...
}

Idiomatic way to ensure many values are equal

Say I have a list of many primitive variables:
final int a = 3;
final int b = 4;
final int c = 4;
final int d = 4;
final int e = 4;
What's an idiomatic way to make sure they all hold the same value? The obvious way is simply
if (a == b && a == c && a == d && a == e) // ...
But I think this is error prone and hard to read, especially when the variables have proper names, unlike my example.
if ( numCategories == numTypes && numCategories == numColours
&& numCategories == numStyles && numCategories == numPrices) // ...
It would be nice if we could do the comparison like this:
if (a == b == c == d == e)
but obviously a == b resolves to a boolean so we can't compare that to c.
Is there a library function in the JDK or another utility library with maybe a signature somewhat like this?
static boolean areEqual(int... numbers)
then we could use it like so:
if (areEqual(a, b, c, d, e)) //...
I could easily write a function like this myself, but why reinvent the wheel if you don't have to?
Maybe there's another idiomatic way to accomplish this that I'm missing.
Using Streams, you can take advantage of some convenient methods to achieve your goal.
You can use Stream's or IntStream's distinct() combined with count() to find the number of unique elements:
For int variables:
if (IntStream.of(a,b,c,d,e).distinct().count() == 1) {
}
For reference type variables:
if (Stream.of(a,b,c,d,e).distinct().count() == 1) {
}
Another way, which is probably less efficient (but I'll keep it here since it's the first thing I thought about) is creating a Stream of all the elements you want to compare and then collecting them into a Set and checking the size of the Set is 1 (since Set doesn't allow duplicates) :
if (IntStream.of(a,b,c,d,e).boxed().collect(Collectors.toSet()).size() == 1) {
}
or
if (Stream.of(a,b,c,d,e).collect(Collectors.toSet()).size() == 1) {
}
for general Objects.
A naive option is to build methods that receives all the variables as varargs and compare them one after other. If one of them is different you will get false
public static boolean areEqual(int...nums)
{
for (int i = 0 ; i < nums.length - 1 ; ++i) {
if (nums[i] != nums[i + 1]) {
return false;
}
}
return true;
}
Uses
if (areEqual(a, b, c, d, e))
I like this approach. There's no auto-boxing and no magic numbers.
As per the documentation, it's also short-circuiting so therefore potentially more efficient than other methods. More importantly, it's very easy to read.
IntStream.of(a, b, c, d).allMatch(x -> x == e);
Credit to saka1029.

How to avoid code duplication?

Is it possible to avoid code duplication in such cases? (Java code)
void f()
{
int r;
boolean condition = true;
while(condition)
{
// some code here (1)
r = check();
if(r == 0)
break ;
else if(r == 1)
return ;
else if(r == 2)
continue ;
else if(r == 3)
condition = false;
// some code here (2)
r = check();
if(r == 0)
break ;
else if(r == 1)
return ;
else if(r == 2)
continue ;
else if(r == 3)
condition = false;
// some code here (3)
}
// some code here (4)
}
int check()
{
// check a condition and return something
}
A possible solution may be using Exceptions, but that doesn't seem to be a good practice.
Is there any so-called good pattern of program flow control in such cases? For example, a way to call break ; from inside the check() function.
(Possibly in other programming languages)
Some good answers (especially #Garrett's just now) to a tough question but I'll add my $0.02 for posterity.
There is no easy answer here about how to refactor this block without seeing the actual code but my reaction to it is that it needs to be redesigned.
For example, a way to call break ; from inside the check() function. (Possibly in other programming languages)
If you are asking for a different break that Java does not support (without a hack) and having the duplicated check() and various different loop exit/repeat code indicates to me that this is a large and complicated method. Here are some ideas for you to think about:
Each of the some code here blocks are doing something. If you pull those out to their own methods, how does that change the loop?
Maybe break the loop down into a series of comments. Don't get deep into the code but think about it conceptually to see if a different configuration drops out.
Have you had another developer in your organization who is not involved with this code take a look at it? If you explain in detail how the code works someone they may see some patterns that you are not since you are in the weeds.
I also think that #aix's idea of a finite state machine is a good one but I've needed to use this sort of mechanism very few times in my programming journeys -- mostly during pattern recognition. I suspect that a redesign of the code with smaller code blocks pulled into methods will be enough to improve the code.
If you do want to implement the state machine here are some more details. You could have a loop that was only running a single switch statement that called methods. Each method would return the next value for the switch. This doesn't match your code completely but something like:
int state = 0;
WHILE: while(true) {
switch (state) {
case 0:
// 1st some code here
state = 1;
break;
case 1:
state = check();
break;
case 2:
return;
case 3:
break WHILE;
case 4:
// 2nd some code
state = 1;
break;
...
}
}
Hope some of this helps and best of luck.
The best way to avoid this duplication is not to let it happen in the first place by keeping your methods small and focused.
If the // some code here blocks are not independent, then you need to post all the code before someone can help you refactor it. If they are independent then there are ways to refactor it.
Code smell
First of all, I second aix's answer: rewrite your code! For this, the state design pattern might help. I would also say that using break, continue and return in such a way is just as much a code smell as the code duplication itself.
Having said that, here is a solution, just for fun
private int r;
void f()
{
distinction({void => codeBlock1()}, {void => codeBlock4()}, {void => f()},
{void => distinction( {void => codeBlock2()},{void => codeBlock4()},
{void => f()}, {void => codeBlock3()} )
});
}
void distinction( {void=>void} startingBlock, {void=>void} r0Block, {void=>void} r2Block, {void=>void} r3Block){
startingBlock.invoke();
r = check();
if(r == 0)
r0Block.invoke();
else if(r == 1)
{}
else if(r == 2)
r2Block.invoke();
else if(r == 3)
// if condition might be changed in some codeBlock, you still
// would need the variable condition and set it to false here.
r3Block.invoke();
}
This uses closures. Of course the parameters r0Block and r2Block could be ommited and instead codeBlock4() and f() hard-coded within distinction(). But then distinction() would only be usable by f(). With Java <=7, you would need to use an Interface with the method invoke() instead, with the 4 implementations codeBlock1 to codeBlock4. Of course this approach is not at all readable, but so general that it would work for any business logic within the codeBlocks and even any break/return/continue-orgy.
Not really.
The second continue is redundant (your code would continue anyway).
Try using the Switch statement. It will make your code more readable.
One nicer way to do it would be to use switch statements, something like this:
void f()
{
int r;
boolean condition = true;
while(condition)
{
outerloop:
r = check();
switch(r){
case 0: break outerloop;
case 1: return;
case 2: continue;
case 3: condition = false;
}
You might want to think about re-formulating your logic as a state machine. It might simplify things, and will probably make the logic easier to follow.

Will there be any performance difference in following code?

I want to know whether there is a performance difference in following two code blocks
1>
if(name == null) {
//something
}
if(name != null) {
//something
}
and
2>
if(name == null) {
//something
}
else {
//something
}
The first compares twice, the second compares once. The difference will not be noticeable, but it's there.
after benchmarkint it on 100.000.000 iterations, the first execution costs 719ms and the second 703ms.
I used a modulo so the conditions has to change every turn and avoid precompiled result. Please find the code below. I have noticed that this gap reduces when number of iterations increases.
public static void main(String[] args) {
Date start1 = new Date();
for(int i=0; i<100000000; i++) {
int it = i%2;
if(it == 0) {
double j = Math.random();
j++;
}
if(it != 0) {
double j = Math.random();
j++;
}
}
Date end1 = new Date();
Date start2 = new Date();
for(int i=0; i<10000000; i++) {
int it = i%2;
if(it == 0) {
double j = Math.random();
j++;
} else {
double j = Math.random();
j++;
}
}
Date end2 = new Date();
System.out.println((end1.getTime()-start1.getTime())+" / "+(end2.getTime()-start2.getTime()));
}
Just a brief comment to say that the compiler cannot optimize it in all cases, because name is visible within the first if block therefore it could have been modified in it, so it has to be checked again in the second if condition. Imagine this case:
if (name == null) {
// Does something
name = "Did it.";
}
if (name != null) {
// Does something else
}
It's clearly not equivalent to
if (name == null) {
// Does something
name = "Did it.";
} else {
// Does something else
}
If what you actually mean is that you should do something in one case and something else otherwise, please use if { ... } else { ... } - not just for (minimal) performance improvement, but also because your code should reflect what you actually mean.
Note that the two fragments are not necessarily equivalent, because the first block could re-assign name so that the second condition will also be true.
This can introduce hard to spot bugs, so I suggest that (before thinking about performance), you think about making the variable final if possible and use if/else when it makes sense (i.e. it should enter only one of the two branches) and chained if's when that makes sense (for example when the first if can establish a default value for the next one to use).
Yes there will, on the second one only one condition will be checked and on the first one two conditions would have to be checked.
An if clause that fails its evaluation has to make an "instruction jump" even if there is no else statement follwing it.
Assuming the first if is false, you'd be comparing these 2 execution scenarios:
1>
Check 1st condition
Skip to check 2nd condition
Do "something" inside the 2nd condition
2>
Check condition
Skip to "something" inside the else
Yes becuase both if cases will be evaluated in the first whereas only one if will be evaluated in the second.
yes, there will be a difference: in the second example, tehre's only 1 statement to be proofed, in the first one there are two.
but: the difference in performance will be absolutely minimal, in 99% of the cases you won't even notive any difference - make sure your code is as readable as it can be, thats much more important ;)
yes obviously the second code will perform inconsiderably better, because there is only one condition to check
I believe the compiler is smart enough to notice that the second if in the first example is redundant, so there won't be any performance change

Categories

Resources