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
Related
I want to be able to break out of an if statement (A) if c() is true.
I sketched some code here, which would do what I want, however with a very ugly loop.
Is there any way I can do the equivalant, as fast as possible without a loop? Requirements:
c() should only be called if a() and b() are true. They should all be called once.
Without writing or reading an external variable.
//statement A
if (a()) {
//always repeats once, dirty solution.
for (int i = 0; i < 1; i++) {
if (b()) {
if (c()) {
break;
} else {
//code
}
}
//code (if b() and c() are true, then this should be unreachable.)
}
}
I am going to repeat this code about 1000 times a second, for hours. So it that is the reason behind the performance.
An if statement can be labelled (as can all statements). You can then use a labelled break to jump to after the if:
someLabel: if (condition) {
// ...
break someLabel;
// ...
}
// It will continue from here.
However, this is not a very standard thing to do: consider restructuring your code so you can avoid having to use this.
I'd extract this logic and use return which works as break for a method, depending on what you want and what the signature of the function is, you want to use return alone, or with null or Optional.empty() or even something else
public void method() {
if (a() && b() && c()) {
return;
}
// unreachable if any of a(), b() or c() are false
}
try rewriting the inner condition in the way: b and (not c)
I've been working on a codebase in which the following structure is quite common:
String value = null;
try {
value = pojoClass.getValue().getANumberOfFunctions();
} catch (Exception e) {
//ignore
}
if (value != null) {
//stuff going on
}
Just to point out: The surrounded code would only throw an exception if the pojo or any of its nested objects is null. There's no database access inside or anything else more complex than a chain of "get" functions.
For what I know, throwing an exception is more expensive in performance terms than doing several null checkings. I can understand (up to a certain point) doing this if there are several objects that could being null for simplicity's sake (Although not for debug's sake), but usually the code I've seen comprises several lines of initializations, try/catches that could easily go into a simple if statement (as usually "else" means do nothing).
Am I missing something, is this "lazy programming", there's something going on above my understanding here?
If you are using Java 8, I'd recommend using the Optional class. It allows you to do something conditionally depending if object is present(not null) or not in a one line way. Example:
static class A {
private B b;
public A(B b) {
this.b = b;
}
public B getB() {return b;}
}
static class B {
private String s;
public B(String s) {
this.s = s;
}
public String getS() {
return s;
}
}
public static void main(String[] args) {
A a1 = new A(new B("a1"));
A a2 = new A(null);
Optional.ofNullable(a1).map(A::getB).map(B::getS).ifPresent(s->{
System.out.println(s);
});
Optional.ofNullable(a2).map(A::getB).map(B::getS).ifPresent(s->{
//this won't be executed
System.out.println(s);
});
}
What you presented is simply bad code, a variant of odd ball solution:
The same problem (here check for null) is solved in different ways.
You should stick with one version only.
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.
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
}
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.