Java compiler is smart enough to reset the source code when it generates the class file. Below is an example to understand this. I have created one java file Compiler.java compiler generates class file of this file as Compiler.class.
Compiler .java
public class Compiler {
public static void main(String[] args) {
boolean a = false;
boolean b = true;
{// block1
if (a) {
System.out.println("I am in if");
} else if (b) {
System.out.println("I am in else if");
} else {
System.out.println("I am in else");
}
}
{// block2
if (a) {
} else if (b) {
} else {
}
}
}
}
Compiler .class
public class Compiler {
public static void main(String[] args) {
boolean a = false;
boolean b = true;
if (a) {
System.out.println("I am in if");
} else if (b) {
System.out.println("I am in else if");
} else {
System.out.println("I am in else");
}
if (!a) {
}
}
}
If one can observe the diffence between block1 and block2 in generated class file. One can understand that how java compiler work in smart way. Compiler checks the first “if else if” conditional statments in block1 and finds there are something to execute within these statement(i.e print statements) so it generate block1 as smilar as in java source . In second block , I mean in block2 compiler finds there is nothing to execute within if -esle if statements so it converts and reset the block2 as you can see class file above. Compiler simply converts the “if else if block” to if statement which will be executed or not be executed depending on boolean value.
In second block if statement also contains negation. Could somebody explain this ? Thanks is advance.
Looks like the compiler's seeing there's some code in the first-level 'else' of the block2, and nothing in the matching if, thus reverting the condition to reducing the unnecessary 'if-else' to a simple 'if'.
It then moves on in depth on the second-level if-else, finds the code would do nothing no matter the variables state, thus removing the whole second-level if-else.
At this point, the now-alone first-level 'if' should contain the second-level block code, but that block just was entirely removed and the compiler didn't "come back" to check it again, thus leaving the first 'if' empty.
Related
Ok so in my program I have two classes, LinkPhone.java, and Frame.java. In the LinkPhone part it calls a function to determine if it is true, and then if it is do something. But then I call the function and use an If statement to check it, it recalls the statement from the If statement. Like in the console it says "DEBUG: Frame init success" twice. Why does it call the function twice and how would I fix it?
LinkPhone.java:
Frame.initFrame();
if(Frame.initFrame() == true){
return;
} else {
return;
}
Frame.java:
public static boolean initFrame(){
try {
JFrame frame = new JFrame("Link Phone");
System.out.println("DEBUG: Frame init success");
return true;
} catch (Exception e) {
System.out.println("DEBUG: Frame init failed!!!");
return false;
}
}
You're calling your method twice!
Frame.initFrame();
if(Frame.initFrame() == true){
return;
} else {
return;
}
Just call it once:
// Frame.initFrame(); // no need for this one
if(Frame.initFrame()){
// hopefully you do more in here!
// return;
} else {
// hopefully you do more in here!
// return;
}
return;
Some side notes:
I would avoid calling a class "Frame" since that would clash with a class that is part of the Java core classes. Give it a more descriptive name to avoid future problems.
It looks like you're calling static methods. This is OK if indicated, but over-use of static methods and variables risks increasing the connectedness of your program, i.e., it can increase code coupling, something that in larger programs can lead to increased complexity and risk of bugs. Java is an OOP language for a reason, since proper use of OOP techniques helps hide data, reducing bugs and increasing code re-use.
Both of your if and else code blocks have a return call. Better to simplify the code and get the return calls out of the blocks. Simply call return after the both blocks.
Again hopefully your if and else blocks hold more code than just matching return statements.
You need to keep hold of the result from the first time you call the method:
boolean result = Frame.initFrame();
if(result) {
return;
} else {
return;
}
Yes. Every time your program executes Frame.initFrame() it calls the method. (That's what the () syntax means)
If you want to call it once you can do this (without the extra call before it):
if(Frame.initFrame() == true) {
or this, if you prefer having the method call on a separate line:
boolean result = Frame.initFrame();
if(result == true) {
It's called twice because you write Frame.initFrame() twice.
Frame.initFrame(); //Once
if(Frame.initFrame() /* Twice */ == true){
return;
} else {
return;
}
If you only meant to call it once and want to store the result, try this:
boolean ok = Frame.initFrame();
if(ok){ //Use result of call
//Do stuff in the event the initting went correctly
return;
} else {
//Do stuff in the event the initting failed
return;
}
Or, event more compactly:
if(Frame.initFrame()){ //Use result of call
//Do stuff in the event the initting went correctly
return;
} else {
//Do stuff in the event the initting failed
return;
}
Is there a way to identify whether the following method executed completely or returned halfway through(i.e at line no 3)
static int a=0;
static void test(){
if(a>10){
return;
}
a++;
}
The method was invoked by another method.(a might have been changed by it)
I cannot change the method declaration. I am dealing with an object I created from a java file created by someone else. I am not allowed to change the original file
Your method does almost nothing and no there is no way in this example you gave to know if the method returned before complete execution but if you willing to change the function to a boolean type you can return true at complete execution and false at incomplete.
static boolean test()
{
if(a>10)
return false;
a++;
return true;
}
Run the code under debugger like jdb and set the breakpoint on the internal return statement. If the program stops at this breakpoint, this obviously means that it would return through that statement.
To make things more automated, you could try to launch the debugger and control the debugger from a Java program through Runtime. This would make the approach applicable for more use cases, while not for all.
You could use
void test(int a) {
if (a > 10) {
return;
}
a++;
System.out.println("test executed completely!");
}
Or if you want to use the information programmatically
private boolean executedCompletely;
void test(int a) {
executedCompletely = false;
if (a > 10) {
return;
}
a++;
executedCompletely = true;
}
When you use your test method, you can check whether it ran completely this way:
int initialA = a;
test();
int finalA = a;
if (finalA != initialA) {
//a has been changed, therefore the method ran completely
} else {
//a has not been changed, therefore it was not incremented, therefore the method did not run completely
}
So I recently came accros this. I was creating an if-else-statement with as it's condition a final boolean variable. Eclipse immediatly told me that the else part of the code was unreachable and therefore dead code. This was my code(compacted).
public static void main(String[] args){
final boolean state = true;
if(state == true){
System.out.println("A");
}else{
System.out.println("B");
}
}
Then I though what would happen if the code stayed the same but the variable wasn't final anymore? So I tried that and this was what happened, nothing no warnings or errors. The code:
public static void main(String[] args){
boolean state = true;
if(state == true){
System.out.println("A");
}else{
System.out.println("B");
}
}
Now I'm wondering, why is the first case detected and flagged and the second case not?
Thank you in advance.
Try this as an alternative.
public class Test061 {
public static void main(String[] args){
int a = 0;
if(1 == (a+1)){
System.out.println("A");
}else{
System.out.println("B");
}
}
}
There are still no warnings. Why?
Because the compiler does not execute your code. It only can issue a warning when it sees some "constants" or "constant expressions". Apparently when you put final the compiler then knows that this value cannot change. While if you use "real variables" or "variable expressions", it doesn't know because it doesn't execute your code (to see what the value of state or (a+1) is at this line). So in the latter case, you get no warnings. Hope this makes more sense now.
Think of it this way: the compiler does some code analysis. The first basic pattern is detected by this analysis, while the second pattern is not (probably as it's not that basic).
final means that something cannot be changed, so likely it was flagged because it can never and will never reach that else statement.
On a side note, you never have to do if(Boolean == true) you can just do if(Boolean)
The compiler does some optimization for final variable as shown below and in that case compiler knows that else part will never reached because final variable can't be changed later.
if (true) {
System.out.println("A");
} else {
System.out.println("B");
}
Read more JLS §4.12.4. final Variables
Find more possibilities for Unreachable code compiler error
First example:
When we use final keyword with a variable and assign a value to the variable, then that value can't change again. final boolean state = true; It can't have a value of "false".
Second example:
Here the variable state is not final. It has the possibility to get a value of "false".
So the different behavior is because of the final keyword.
Why java allows to use the labled break inside a method?
Is there any special purpose or use of this?
I thought it can be only use within the loops and swtches.
public void testMeth(int count){
label:
break label;
}
But below gives a compiler error.
public void testMeth(int count){
break; // This gives an Error : break cannot be used outside of a loop or a switch
}
I don't know the why, but the behaviour is specified in the Java Language Specification #14.15:
Break with no label
A break statement with no label attempts to transfer control to the innermost enclosing switch, while, do, or for statement of the immediately enclosing method or initializer; this statement, which is called the break target, then immediately completes normally.
If no switch, while, do, or for statement in the immediately enclosing method, constructor, or initializer contains the break statement, a compile-time error occurs.
Break with label (emphasis mine)
A break statement with label Identifier attempts to transfer control to the enclosing labeled statement (§14.7) that has the same Identifier as its label; this statement, which is called the break target, then immediately completes normally. In this case, the break target need not be a switch, while, do, or for statement.
Breaks with label enable you to redirect the code after a whole block (which can be a loop), which can be useful in the case of nested loops. It is however different from the C goto statement:
Unlike C and C++, the Java programming language has no goto statement; identifier statement labels are used with break (§14.15) or continue (§14.16) statements appearing anywhere within the labeled statement.
You can use this to break out of nested loops immediately:
out: {
for( int row=0; row< max; row++ ) {
for( int col=0; col< max; col++ )
if( row == limit) break out;
j += 1;
}
}
Using break outside of loops does not make a whole lot of sense, where would you be breaking of? To break out of a void function you can use return as adarshr points out.
You can use labeled breaks to get out of nested loops, like here.
Because there is the return statement for use outside the loops!
public void testMeth(int count){
if(count < 0) {
return;
}
// do something with count
}
I found one crazy use by my self.
public void testMeth(int count){
label: if (true) {
System.out.println("Before break");
if (count == 2) break label;
System.out.println("After break");
}
System.out.println("After IF");
}
OR
public void testMeth(int count){
namedBlock: {
System.out.println("Before break");
if (count == 0) break namedBlock;
System.out.println("After break");
}
System.out.println("After Block");
}
This ignores the "After break".
Here is yet another example of when labels are useful outside the context of a loop:
boolean cond1 = ...
if (cond1) {
boolean cond1 = ...
if (cond2) {
boolean cond3 = ...
if (cond3) {
bar();
} else {
baz();
}
} else {
baz();
}
} else {
baz();
}
...becomes...
label: {
boolean cond1 = ...
if (cond1) {
boolean cond1 = ...
if (cond2) {
boolean cond3 = ...
if (cond3) {
bar();
break label;
}
}
}
baz();
}
A contrived example, obviously, but slightly more readable. My recommendation is that if you feel the need to use a label, pretty much ever, you should otherwise refactor the code.
I strongly discurage the use of a labled break statement. It is almost as bad as a GOTO. A single break; is ok/necessary to end a loop or switch etc. But to my experience: The need for such a labled break is an indicator for a bad control-flow-design.
In most cases, a well placed exception would be more meaningful. But just, if the "Jump-Condition" can be seen as an Error. If you lable your method correctly, you can influence, what can be seen as an Error or not.
If your method is called "getDrink()" and it returns a "milk" object, it is ok. But if your method is called "getWater()", it should throw an Exception instead of returning milk...
So instead of:
public class TestBad {
public static void main(String[] args) {
String[] guys = {"hans", "john"};
myLabel: {
for(String guy: guys) {
String drink = getDrink(guy);
if(drink.equals("milk")) {
// Handle "milk"??
break myLabel;
}
// Do something with "non-milk"
}
}
// Success? Non Success??
}
private static String getDrink(String guy) {
if(guy.equals("hans"))
return "milk";
else
return "water";
}
}
You should use:
public class TestGood {
public static void main(String[] args) {
String[] guys = {"hans", "john"};
try {
handleStuff(guys);
} catch (Exception e) {
// Handle Milk here!
}
}
private static void handleStuff(String[] guys) throws Exception {
for(String guy: guys) {
String drink = getWater(guy);
// Do something with "water"
}
}
private static String getWater(String guy) throws Exception {
if(guy.equals("hans"))
// The method may NEVER return anything else than water, because of its name! So:
throw new Exception("No Water there!");
else
return "water";
}
}
Fazit: Instead of nesting Blocks into Blocks or multiple loops, one should nest methods and use proper exception handling. This enhances readability and reusability.
Imagine you have a Java code like this :
public class MyClass {
public static Object doSmthg(Object A,Object B){
if(smthg){ //if is given has an example, it can be any thing else
doSmthg;
GOTO label;
}
doSmthg;
label;
dosmthg1(modifying A and B);
return an Object;
}
}
I am generating the Code automatically. When the generator arrive at the moment of generating the goto (and it does not know it is in the if block), it has no knowledge of what will be afterwards.
I tried using labels,break,continue but this does not work.
I tried to use an internal class (doing dosmthg1) but A and B must be declared final. The problem is A and B have to be modified.
If there is no other solutions, I will have to propagate more knowledge in my generator. But I would prefer a simpler solution.
Any ideas ?
Thanks in advance.
public static Object doSmthg(Object A,Object B){
try {
if(smthg){ //if is given has an example, it can be any thing else
doSmthg;
throw new GotoException(1);
}
doSmthg;
} catch (GotoException e) {
e.decrementLevel();
if (e.getLevel() > 0)
throw e;
}
dosmthg1(modifying A and B);
return an Object;
}
One can do gotos with exception, but for targeting the correct "label" one either has to check the exception message or think of a nesting level.
I do not know whether I find this not uglier.
You can add a dummy loop around the block preceding the label, and use labeled break as an equivalent of goto:
public static Object doSmthg(Object A,Object B){
label:
do { // Labeled dummy loop
if(smthg){ //if is given has an example, it can be any thing else
doSmthg;
break label; // This brings you to the point after the labeled loop
}
doSmthg;
} while (false); // This is not really a loop: it goes through only once
dosmthg1(modifying A and B);
return an Object;
}
If you want to jump over something, like so:
A
if cond goto c;
B
c: C
you can do this like
while (true) {
A
if cond break;
B
}
C