I am trying to implement a tail-recursive factorial calculator but I am still getting a stack overflow. Can anyone help me out in figuring out why?
I have read that Java 8 supports Tail call optimization, but I am thinking I must not be implementing it correctly.
I have read that it is possible using lambda expressions. I am not sure I fully understand this concept but I am still reading.
I am just looking for any advice on how to get this to use real tail call optimization, lambda expressions or however I can.
code:
package factorielRecursiveTerminale;
import java.math.BigInteger;
import java.util.Scanner;
public class factorielRecursiveTerminale {
public static BigInteger factoriel(BigInteger n, BigInteger m) {
if (n.compareTo(BigInteger.ZERO) < 1) return m;
return factoriel(n.subtract(BigInteger.ONE), n.multiply(m));
}
public static BigInteger fact(int n) { //convertir l'entree en BigInteger et lancer la recursion
if(n < 0) {
return BigInteger.valueOf(-1);
}
BigInteger b = BigInteger.valueOf(n);
return factoriel(b, BigInteger.ONE);
}
public static void runBigFact() { //gestion des erreurs + boucle d'entree de valeurs.
String valeurRecu = "";
int valeur;
BigInteger resultat;
System.out.println("Calcul Factoriel\n");
while(!valeurRecu.contentEquals("q")){
System.out.println("Entrer la valeur a calculer (q - quitter) : ");
Scanner entree = new Scanner(System.in);
valeurRecu = entree.nextLine();
if (valeurRecu.contentEquals("q")) entree.close();
else {
try {
valeur = Integer.parseInt(valeurRecu);
}catch (NumberFormatException e){
System.out.println("Pas un entier. Essayer encore.\n");
continue;
}
try {
resultat = fact(valeur);
if(resultat.compareTo(BigInteger.valueOf(-1)) == 0) {
System.out.println("Valeur negative. Essayer encore.\n");
}
else System.out.println("Factoriel " + valeur + " -> " + fact(valeur) + "\n");
} catch(StackOverflowError e) {
System.out.println("Depassement de la pile. Essayer un entier plus petit.\n");
continue;
}
}
}
System.out.println("Au revoir! :)\n");
}
public static void main(String[] args) {
runBigFact();
}
}
I have read that JAVA 8 supports Tail call optimization, but I am thinking I must not be implementing it correctly.
Then you have read wrong. Or, you've read a correct statement but didn't interpret it correctly.
Java, the language, does not support tail call recursion. It never has. It probably never will*.
However, java, the VM, has a few features that make it easier for other, non-java languages which nevertheless compile into class files to run on a java runtime, to support TCO. That's, presumably, what you read about.
I am just looking for any advice on how to get this to use real tail call optimization, lambda expressions or however I can.
Write it in scala or some such.
Seriously, how does java not have TCO???
TCO is pricey: Java has this rule that when errors occur you get a stack trace, and stack traces are a well defined concept that, crucially, tracks 1 stack frame for each logical call. This cannot continue if TCO exists. There are options, of course: Each individual frame on stack could gain a 'counter' so that the stack trace remains a smallish memory footprint while correctly representing 'and this sequence of calls has recurred 8190581 times'. It's also a boatload of text in the lang spec about how it works, when it does and doesn't kick in, and what it all means, and any additional pages in the spec are maintenance burdens forever - it's not a case of 'it is strictly superior to add TCO to java so when we get around to it, slam dunk, and any Pull Requests with the feature will be integrated immediately'.
Furthermore, TCO as a model is a way of doing things, but it's not the only way. For anything that could be written as a TCO-recursive application, it is generally not all that difficult to refactor that into a loop-based, non-recursing algorithm. Contrast to, say, yield-based async operations, where you can of course rewrite (hey, it's all turing machines), but the rewrite would be difficult, and the resulting code considerably harder to understand. I don't want to get into the value (or lack thereof) of yield/async style coding, just making the point that TCO does not have that veneer of 'ah, but, if TCO is a good idea, then only TCO will do'.
I don't have the links off-hand, but statements in this vein have been said by those who hold quite a bit of sway over the future of java, such as Brian Goetz, Mark Reinhold, etc. If you are really dedicated to try to see this added to java, I suggest you search the web for these statements and then try to shape some arguments specifically to address the concerns they state. Because if you can't convince those folks, it's never going to happen.
So what do I do in java?
Don't use recursion; use while or for instead.
UPDATE: What about that blog entry?
In comments you have linked to this blog entry. That's.. not TCO.
That's using lambdas to write a framework that lets you more or less emulate TCO, but it isn't TCO. The blog describes a little framework - and thus, you need all that stuff they pasted: The TailCall interface in particular.
That code works like this:
Your 'recursive' method isn't recursive at all, it always returns quickly without calling itself.
It returns a lambda which may call itself, though. But, as we just covered, calling yourself returns quickly without recursion, and it returns a function.
The framework will execute your function, which produces, usually, a function (or an actual result). It loops (so no recursion), repeatedly applying the process of: "Call the function. If it returns a function, then loop. If it returns a result, okay, that's the result we wanted so just return that".
That describes what TCO tries to accomplish (repeatedly invoke the same function over and over with different arguments until a hardcoded edge case is reached, and then reverse back out), but doesn't use TCO to do it.
Hence, that blog post saying 'look, TCO in java!' is misleading.
It's like me saying: "Look, paintbrushes on tunnels walls!" and describing how to use cans of spray paint to paint the tunnel wall in a way that looks like it was hand brushed. That is nice, but it's misleading to call it 'paintbrushing a wall'. At best you can say: "Looking to make paintbrush style art in tunnels? Well, you can't, and I can't fix that, but I can tell you how to get similar results!".
*) Never say never and all that, but I mean: There are no plans on the horizon, and the plans for the future of the java platform go many years into the future and are quite public. I'd take 1 to 40 odds on 'java (the language) does not have tail call recursion within 4 years' and still take that bet.
You may find this useful. I was able to get some improvement over your previous attempt but in this case it is not the size of the BigInteger object that causes the SO. On my machine, both of these methods result in a Stack Overflow between 14000 and 15000 for n. The simpleLong is just a basic recursive method to decrement the Long and it still blows up at 15000. Both succeed at 14000.
public static void main(String[] args) {
count = 0;
long n = 14000;
simpleLong(n);
factoriel(BigInteger.valueOf(n));
}
static BigInteger factoriel(BigInteger n) {
if (n.compareTo(BigInteger.TWO) == 1) {
return factoriel(n.subtract(BigInteger.ONE)).multiply(n);
}
return n;
}
static long simpleLong(long n) {
if (n > 1) {
simpleLong(n-1);
}
return n;
}
Related
I am trying to implement a tail-recursive factorial calculator but I am still getting a stack overflow. Can anyone help me out in figuring out why?
I have read that Java 8 supports Tail call optimization, but I am thinking I must not be implementing it correctly.
I have read that it is possible using lambda expressions. I am not sure I fully understand this concept but I am still reading.
I am just looking for any advice on how to get this to use real tail call optimization, lambda expressions or however I can.
code:
package factorielRecursiveTerminale;
import java.math.BigInteger;
import java.util.Scanner;
public class factorielRecursiveTerminale {
public static BigInteger factoriel(BigInteger n, BigInteger m) {
if (n.compareTo(BigInteger.ZERO) < 1) return m;
return factoriel(n.subtract(BigInteger.ONE), n.multiply(m));
}
public static BigInteger fact(int n) { //convertir l'entree en BigInteger et lancer la recursion
if(n < 0) {
return BigInteger.valueOf(-1);
}
BigInteger b = BigInteger.valueOf(n);
return factoriel(b, BigInteger.ONE);
}
public static void runBigFact() { //gestion des erreurs + boucle d'entree de valeurs.
String valeurRecu = "";
int valeur;
BigInteger resultat;
System.out.println("Calcul Factoriel\n");
while(!valeurRecu.contentEquals("q")){
System.out.println("Entrer la valeur a calculer (q - quitter) : ");
Scanner entree = new Scanner(System.in);
valeurRecu = entree.nextLine();
if (valeurRecu.contentEquals("q")) entree.close();
else {
try {
valeur = Integer.parseInt(valeurRecu);
}catch (NumberFormatException e){
System.out.println("Pas un entier. Essayer encore.\n");
continue;
}
try {
resultat = fact(valeur);
if(resultat.compareTo(BigInteger.valueOf(-1)) == 0) {
System.out.println("Valeur negative. Essayer encore.\n");
}
else System.out.println("Factoriel " + valeur + " -> " + fact(valeur) + "\n");
} catch(StackOverflowError e) {
System.out.println("Depassement de la pile. Essayer un entier plus petit.\n");
continue;
}
}
}
System.out.println("Au revoir! :)\n");
}
public static void main(String[] args) {
runBigFact();
}
}
I have read that JAVA 8 supports Tail call optimization, but I am thinking I must not be implementing it correctly.
Then you have read wrong. Or, you've read a correct statement but didn't interpret it correctly.
Java, the language, does not support tail call recursion. It never has. It probably never will*.
However, java, the VM, has a few features that make it easier for other, non-java languages which nevertheless compile into class files to run on a java runtime, to support TCO. That's, presumably, what you read about.
I am just looking for any advice on how to get this to use real tail call optimization, lambda expressions or however I can.
Write it in scala or some such.
Seriously, how does java not have TCO???
TCO is pricey: Java has this rule that when errors occur you get a stack trace, and stack traces are a well defined concept that, crucially, tracks 1 stack frame for each logical call. This cannot continue if TCO exists. There are options, of course: Each individual frame on stack could gain a 'counter' so that the stack trace remains a smallish memory footprint while correctly representing 'and this sequence of calls has recurred 8190581 times'. It's also a boatload of text in the lang spec about how it works, when it does and doesn't kick in, and what it all means, and any additional pages in the spec are maintenance burdens forever - it's not a case of 'it is strictly superior to add TCO to java so when we get around to it, slam dunk, and any Pull Requests with the feature will be integrated immediately'.
Furthermore, TCO as a model is a way of doing things, but it's not the only way. For anything that could be written as a TCO-recursive application, it is generally not all that difficult to refactor that into a loop-based, non-recursing algorithm. Contrast to, say, yield-based async operations, where you can of course rewrite (hey, it's all turing machines), but the rewrite would be difficult, and the resulting code considerably harder to understand. I don't want to get into the value (or lack thereof) of yield/async style coding, just making the point that TCO does not have that veneer of 'ah, but, if TCO is a good idea, then only TCO will do'.
I don't have the links off-hand, but statements in this vein have been said by those who hold quite a bit of sway over the future of java, such as Brian Goetz, Mark Reinhold, etc. If you are really dedicated to try to see this added to java, I suggest you search the web for these statements and then try to shape some arguments specifically to address the concerns they state. Because if you can't convince those folks, it's never going to happen.
So what do I do in java?
Don't use recursion; use while or for instead.
UPDATE: What about that blog entry?
In comments you have linked to this blog entry. That's.. not TCO.
That's using lambdas to write a framework that lets you more or less emulate TCO, but it isn't TCO. The blog describes a little framework - and thus, you need all that stuff they pasted: The TailCall interface in particular.
That code works like this:
Your 'recursive' method isn't recursive at all, it always returns quickly without calling itself.
It returns a lambda which may call itself, though. But, as we just covered, calling yourself returns quickly without recursion, and it returns a function.
The framework will execute your function, which produces, usually, a function (or an actual result). It loops (so no recursion), repeatedly applying the process of: "Call the function. If it returns a function, then loop. If it returns a result, okay, that's the result we wanted so just return that".
That describes what TCO tries to accomplish (repeatedly invoke the same function over and over with different arguments until a hardcoded edge case is reached, and then reverse back out), but doesn't use TCO to do it.
Hence, that blog post saying 'look, TCO in java!' is misleading.
It's like me saying: "Look, paintbrushes on tunnels walls!" and describing how to use cans of spray paint to paint the tunnel wall in a way that looks like it was hand brushed. That is nice, but it's misleading to call it 'paintbrushing a wall'. At best you can say: "Looking to make paintbrush style art in tunnels? Well, you can't, and I can't fix that, but I can tell you how to get similar results!".
*) Never say never and all that, but I mean: There are no plans on the horizon, and the plans for the future of the java platform go many years into the future and are quite public. I'd take 1 to 40 odds on 'java (the language) does not have tail call recursion within 4 years' and still take that bet.
You may find this useful. I was able to get some improvement over your previous attempt but in this case it is not the size of the BigInteger object that causes the SO. On my machine, both of these methods result in a Stack Overflow between 14000 and 15000 for n. The simpleLong is just a basic recursive method to decrement the Long and it still blows up at 15000. Both succeed at 14000.
public static void main(String[] args) {
count = 0;
long n = 14000;
simpleLong(n);
factoriel(BigInteger.valueOf(n));
}
static BigInteger factoriel(BigInteger n) {
if (n.compareTo(BigInteger.TWO) == 1) {
return factoriel(n.subtract(BigInteger.ONE)).multiply(n);
}
return n;
}
static long simpleLong(long n) {
if (n > 1) {
simpleLong(n-1);
}
return n;
}
I have to use a method to call a joiner with " " as parameter for concatenate string a and b, I have to check if either of the sides are empy ("").
Both codes works, but i don't get why my reviewer want me to do it in his way. If someone could explain me the benefits of it it would be great.
My method.
public static String join(String a, String b) {
StringJoiner sj = new StringJoiner(" ");
if (a.endsWith("dieci") || a.endsWith("veinti")) {
return a + b;
}
if (a.equals("")) {
return b;
}
if (b.contentEquals("")) {
return a;
}
sj.add(a);
sj.add(b);
return sj.toString();
}
His method.
public static String join(String a, String b) {
if (a.endsWith("dieci") || a.endsWith("veinti")) {
return a + b;
}
return Stream.of(a, b).filter(s ->!s.isEmpty()).collect(Collectors.joining(" "));
}
His is much simpler; in one line it essentially says:
Take Strings a and b, get rid of the empty ones, and join the remaining ones with spaces, returning the result.
This makes it very clear to see the intention of the code. It also prevents errors, as it would be much easier to have a typo or logic error in your spread-out code that breaks down the implementation into multiple different cases.
Admittedly, this may be harder to understand than your code to start with, as beginners likely won't understand streams. But once you understand them, it is certainly easier to read (at least in this scenario, but not always), and it makes writing such methods much easier. So, it is better to learn such Java constructs now and use them, rather than later.
His code is also much more flexible. If you had to make the method join three Strings, the only modification to his method would be to change Stream.of(a, b) to Stream.of(a, b, c). Your method would require much more changes.
Also, using isEmpty() is clearer than .equals("") as it says what you're doing in more natural English terms. And this again prevents typos, as you could accidentally do .equals(" ") (with a space) or something.
Also, why do you use two different methods (equals and contentEquals) to do the same thing? That is confusing. His method doesn't do that.
First of all, there is always an element of opinion in this kind of thing. And probably communication and personalities too. Is it really worth your effort arguing? If your reviewer wants to rewrite your code in reviews, what's the harm1?
Now to the substance.
On the face of it, your reviewer's code is clearly both more concise and easier to understand once you are familiar with Java 8 streams. And I imagine that the assumption is that everybody working on this project should be familiar with, if not fluent in streams2. It clearly deals with the edge cases more neatly.
I would also argue that your use of a StringJoiner to concatenate 2 strings with a space between is overkill. A simple concatenation expression is both more efficient and easier to understand than what you are doing.
return a + " " + b;
The only other point of difference is performance:
It is not clear to me which one will perform better. You would need to benchmark the two versions to be sure.
If you are optimizing for CPU cycles used or garbage generated, neither versions is optimal.
(But note that you should only optimize for performance if you have concrete evidence that the performance of this method is critical to the overall application. If it isn't then optimization is most likely a waste of your time, and a few minutes / hours of your time is probably more costly that a few CPU cycles wasted in millions.)
Just for info, if I needed to optimize for performance I would write the method like this:
public static String join(String a, String b) {
if (a.isEmpty()) {
return b;
} else if (b.isEmpty()) {
return a;
} else if (a.endsWith("dieci") || a.endsWith("veinti")) {
return a + b;
} else {
return a + " " + b;
}
}
I will leave the reader to figure out what I have done, and why. And what (possibly unwarranted) assumptions I have made.
1 - The harm is if he is screwing up your or his productivity ...
2 - Java 8 is 4+ years old now. Plenty of time for a professional to learn to use its new features. And if you are fresh out of Uni and the didn't teach you Java 8 streams ... learn them ASAP!
public static int rFib(int n) {
if(n == 0) {
return 0;
}
if(n == 1) {
return 1;
}
return n + rFib(n-1);
}
I am trying to find the largest number that will compute in under 60 seconds. Then I will use an iterative method to compare. Any number greater than 10,000 gives a stack-overflow error. How do I avoid this?
One solution to this recursion problem is to break the recursion using dynamic programming. For example, memoization can be applied and allow you to implement it like
private static Map<Integer, Integer> memo = new HashMap<>();
static {
memo.put(0, 0);
memo.put(1, 1);
}
public static int rFib(int n) {
if (memo.containsKey(n)) {
return memo.get(n);
}
int r = rFib(n - 2) + rFib(n - 1);
memo.put(n, r);
return r;
}
Unfortunately, you have come across the problem which is both the single most-used example for understanding recursion and almost the single worst application to apply recursion to.
It's really simple to understand recursion from the fibonacci because it's a really trivial recursive algorithm for you to explain to somebody and understand... Which means it's great for programming recursion, right? Unfortunately, no.
I apologize if I'm going to tell you things you already know, but I know that fibonacci is one of the first examples in introductory programming so I'm assuming that's where you're coming from.
There's a thing in programming called a stack. It's literally called this because it's like a stack of papers. When you call a function, it puts onto the stack all the information needed to call the function, pass the arguments, and know how to return from the function (and some other administrative stuff). When that function recursively calls itself, it puts another sheet on top of the stack. Then that function puts another sheet. These sheets aren't removed until the function finishes... But since one function can't finish before the other one finishes, it just grows and grows and grows.
And the stack is only so big. Purposely. To avoid this problem.
Normally, recursion isn't used for such deep problems. (Tail-call-recursive people: ignore this; if you don't know what tail-call-recusion is: also ignore this.)
The way to fix this is to not do it. It's generally recognized that in nearly every arbitrarily-recursive function application, a for loop will work better (and faster).
I just learned today that the following Java code is perfectly legal:
myBlock: {
/* ... code ... */
if (doneExecutingThisBlock())
break myBlock;
/* ... more code ... */
}
Note that myBlock isn't a loop - it's just a block of code I've delimited with curly braces.
This seems like a rather strange feature to have. It means that you can use a named break to break out of an if statement or anonymous block, though you can't normally use a break statement in these contexts.
My question is this: is there a good reason for this design decision? That is, why make it so that you can only break out of certain enclosing statements using labeled breaks but not regular breaks? And why allow for this behavior at all? Given how (comparatively) well-designed Java is as a language I would assume there's a reason for this, but I honestly can't think of one.
It is plausible that this was done for simplicity. If originally the labeled break can only break loop statements, then it should be immediately clear to language designer that the restriction isn't necessary, the semantics work the same for all statements. For the economics of the language spec, and simpler implementation of compilers, or just out of the habit towards generality, labeled break is defined for any statement, not just loop statements.
Now we can look back and judge this choice. Does it benefit programmers, by giving them extra expression power? Seems very little, the feature is rarely used. Does it cost programmers in learning and understanding? Seems so, as evidenced by this discussion.
If you could go back time and change it, would you? I can't say I would. We have a fetish for generality.
If in a parallel universe it was limited to loop statements only, there is still a chance, probably much smaller, that someone posts the question on stackoverflow: why couldn't it work on arbitrary statements?
Think of it as a return statement that returns from the block instead of from the entire function. The same reasoning you apply to object to break being scattered anywhere can also be applied to return being allowed anywhere except at the end of a function.
The issue with goto is that it can jump forward, past code. A labeled break cannot do that (it can only go backwards). IIRC C++ has to deal with goto jumping past code (it is been over 17 years since I cared about that though so I am not sure I am remembering that right).
Java was designed to be used by C/C++ programmers, so many things were done to make it familiar to those developers. It is possible to do a reasonable translation from C/C++ to Java (though some things are not trivial).
It is reasonable to think that they put that into the language to give C/C++ developers a safe goto (where you can only go backwards in the code) to make it more comfortable to some programmers converting over.
I have never seen that in use, and I have rarely seen a labeled break at all in 16+ years of Java programming.
You cannot break forward:
public class Test
{
public static void main(final String[] argv)
{
int val = 1;
X:
{
if(argv.length == 0)
{
break X;
}
if(argv.length == 1)
{
break Y; <--- forward break will not compile
}
}
val = 0;
Y:
{
Sysytem.out.println(val); <-- if forward breaks were allowed this would
print out 1 not 0.
}
}
}
Why make it so that you can only break out of certain enclosing statements using labeled breaks but not regular breaks
Consider:
while (true) {
if (condition) {
break;
}
}
If the break did as you suggest, this code would perform unexpectedly. Breaks would become a lot more difficult to use.
And why allow for this behavior at all?
I don't use it, but it is a feature and allows for certain unique control-flow constructs. I'd ask you, why not allow it?
is there a good reason for this design decision?
Yes. Because it works.
In the labelled break case, the fact that you don't need to be inside a loop or switch lets you to express things that are harder to express in other ways. (Admittedly, people rarely do use labelled break this way ... but that's not a fault of the language design.)
In the unlabelled break case, the behavior is to break out of the innermost enclosing loop or switch. If it was to break out of the innermost enclosing statement, then a lot of things would be much harder to express, and many would probably require a labelled block. For example:
while (...) {
/* ... */
if (something) break;
/* ... */
}
If break broke out of the innermost enclosing statement, then it wouldn't break out of the loop.
There is another possible reason / rationale. Remember that Java was a brand new language and a relatively early adopter of exceptions and exception handling.
Consider this:
try {
/* ... code ... */
if (doneExecutingThisBlock())
throw new OuttaHere();
/* ... more code ... */
} catch (OuttaHere e) {
/* do nothing */
}
According to the dogma, that is bad code. You shouldn't use exceptions for "normal" flow control.
(Pragmatically, that it also very inefficient due to the overheads of exception creation and handling. Exceptions performance was improved significantly in Java 8, I think, but that was ~20 years later.)
Now imagine that you are a language designer, and you feel that you have to provide an alternative to the "exceptions as flow control" anti-pattern. The "break to label" construct does exactly that. Compare the above with the example in the question.
In hindsight, this is unnecessary. The above can be done in other ways; i.e. without labelled break. In practice this construct is used so rarely that many (maybe most) programmers don't even know it exists in Java.
The ability to leave a sequence of statements has been implemented in several programming languages before Java. Two examples:
Algol-68 had exit to terminate the execution of the smallest closed-clause (very loosely speaking, a begin ... end sequence).
BLISS had labelled BEGIN … END blocks, with a LEAVE statement to terminate execution.
Implementations with labels (as in Java) are more flexible in that they can exit nested blocks (or compound statements, or whatever you call them in your language of choice); without the label, you're limited to exiting a single "level" only.
Answering the direct question, "why" -- because it's been found to be a useful construct in other, prior, languages.
Adding to Stephen C's answer, if (something) you cannot break out of a nested loop. These situations do happen in numerical algorithms. One simple example here - you cannot break out of the i-loop without the named for. Hope this helps.
public class JBreak {
private int brj;
public JBreak (String arg) {
brj = Integer.parseInt (arg);
}
public void print () {
jbreak:
for (int i = 1 ; i < 3 ; i++) {
for (int j = 0 ; j < 5 ; j++) {
if ((i*j) == brj)
break jbreak;
System.out.println ("i,j: " + i + "," + j);
}}}
public static void main (String[] args) {
new JBreak(args[0]).print();
}}
It's the "structured" equivalent to a goto, useful in certain circumstances.
I quite often use such a label create named sub-blocks in a method to tightly limit scope of variables or to simply label a block of code which is not appropriate to break out into a separate function. That is, I use it to label a block so that the code structure around braces is preserved. Here's an example in C for a JNI call, and I do the same in Java:
JNIEXPORT void JNICALL Java_xxx_SystemCall_jniChangePassword(JNIEnv *jep, jobject thsObj,
jlong handle, jbyteArray rndkey, jbyteArray usrprf, jbyteArray curpwd, jbyteArray newpwd, jint pwdccs, jint tmosec) {
Message rqs,rpy;
thsObj=thsObj;
SetupRequest: {
memset(&rqs,0,sizeof(rqs));
setOpcode(&rqs,"CHGPWD");
if(!setField(mFldAndLen(rqs.rnd ),null ,jep,rndkey,"Random Key")) {
return;
}
if(!setField(mFldAndLen(rqs.dta.chgpwd.user ),&rqs.dta.chgpwd.userLen ,jep,usrprf,"User Profile")) {
return;
}
if(!setField(mFldAndLen(rqs.dta.chgpwd.curPass),&rqs.dta.chgpwd.curPassLen,jep,curpwd,"Cur Password")) {
return;
}
if(!setField(mFldAndLen(rqs.dta.chgpwd.newPass),&rqs.dta.chgpwd.newPassLen,jep,newpwd,"New Password")) {
return;
}
rqs.dta.chgpwd.ccsid=pwdccs;
}
...
The break statement terminates the labeled statement; it does not transfer the flow of control to the label. Control flow is transferred to the statement immediately following the labeled (terminated) statement.
It seems to be useful to exit nested loops. See http://download.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
It's semantically the same as is there a equivalent of Java's labelled break in C# or a workaround
Today I had a coworker suggest I refactor my code to use a label statement to control flow through 2 nested for loops I had created. I've never used them before because personally I think they decrease the readability of a program. I am willing to change my mind about using them if the argument is solid enough however. What are people's opinions on label statements?
Many algorithms are expressed more easily if you can jump across two loops (or a loop containing a switch statement). Don't feel bad about it. On the other hand, it may indicate an overly complex solution. So stand back and look at the problem.
Some people prefer a "single entry, single exit" approach to all loops. That is to say avoiding break (and continue) and early return for loops altogether. This may result in some duplicate code.
What I would strongly avoid doing is introducing auxilary variables. Hiding control-flow within state adds to confusion.
Splitting labeled loops into two methods may well be difficult. Exceptions are probably too heavyweight. Try a single entry, single exit approach.
Labels are like goto's: Use them sparingly, and only when they make your code faster and more importantly, more understandable,
e.g., If you are in big loops six levels deep and you encounter a condition that makes the rest of the loop pointless to complete, there's no sense in having 6 extra trap doors in your condition statements to exit out the loop early.
Labels (and goto's) aren't evil, it's just that sometimes people use them in bad ways. Most of the time we are actually trying to write our code so it is understandable for you and the next programmer who comes along. Making it uber-fast is a secondary concern (be wary of premature optimization).
When Labels (and goto's) are misused they make the code less readable, which causes grief for you and the next developer. The compiler doesn't care.
There are few occasions when you need labels and they can be confusing because they are rarely used. However if you need to use one then use one.
BTW: this compiles and runs.
class MyFirstJavaProg {
public static void main(String args[]) {
http://www.javacoffeebreak.com/java101/java101.html
System.out.println("Hello World!");
}
}
I'm curious to hear what your alternative to labels is. I think this is pretty much going to boil down to the argument of "return as early as possible" vs. "use a variable to hold the return value, and only return at the end."
Labels are pretty standard when you have nested loops. The only way they really decrease readability is when another developer has never seen them before and doesn't understand what they mean.
I have use a Java labeled loop for an implementation of a Sieve method to find prime numbers (done for one of the project Euler math problems) which made it 10x faster compared to nested loops. Eg if(certain condition) go back to outer loop.
private static void testByFactoring() {
primes: for (int ctr = 0; ctr < m_toFactor.length; ctr++) {
int toTest = m_toFactor[ctr];
for (int ctr2 = 0; ctr2 < m_divisors.length; ctr2++) {
// max (int) Math.sqrt(m_numberToTest) + 1 iterations
if (toTest != m_divisors[ctr2]
&& toTest % m_divisors[ctr2] == 0) {
continue primes;
}
} // end of the divisor loop
} // end of primes loop
} // method
I asked a C++ programmer how bad labeled loops are, he said he would use them sparingly, but they can occasionally come in handy. For example, if you have 3 nested loops and for certain conditions you want to go back to the outermost loop.
So they have their uses, it depends on the problem you were trying to solve.
I've never seen labels used "in the wild" in Java code. If you really want to break across nested loops, see if you can refactor your method so that an early return statement does what you want.
Technically, I guess there's not much difference between an early return and a label. Practically, though, almost every Java developer has seen an early return and knows what it does. I'd guess many developers would at least be surprised by a label, and probably be confused.
I was taught the single entry / single exit orthodoxy in school, but I've since come to appreciate early return statements and breaking out of loops as a way to simplify code and make it clearer.
I'd argue in favour of them in some locations, I found them particularly useful in this example:
nextItem: for(CartItem item : user.getCart()) {
nextCondition : for(PurchaseCondition cond : item.getConditions()) {
if(!cond.check())
continue nextItem;
else
continue nextCondition;
}
purchasedItems.add(item);
}
I think with the new for-each loop, the label can be really clear.
For example:
sentence: for(Sentence sentence: paragraph) {
for(String word: sentence) {
// do something
if(isDone()) {
continue sentence;
}
}
}
I think that looks really clear by having your label the same as your variable in the new for-each. In fact, maybe Java should be evil and add implicit labels for-each variables heh
I never use labels in my code. I prefer to create a guard and initialize it to null or other unusual value. This guard is often a result object. I haven't seen any of my coworkers using labels, nor found any in our repository. It really depends on your style of coding. In my opinion using labels would decrease the readability as it's not a common construct and usually it's not used in Java.
Yes, you should avoid using label unless there's a specific reason to use them (the example of it simplifying implementation of an algorithm is pertinent). In such a case I would advise adding sufficient comments or other documentation to explain the reasoning behind it so that someone doesn't come along later and mangle it out of some notion of "improving the code" or "getting rid of code smell" or some other potentially BS excuse.
I would equate this sort of question with deciding when one should or shouldn't use the ternary if. The chief rationale being that it can impede readability and unless the programmer is very careful to name things in a reasonable way then use of conventions such as labels might make things a lot worse. Suppose the example using 'nextCondition' and 'nextItem' had used 'loop1' and 'loop2' for his label names.
Personally labels are one of those features that don't make a lot of sense to me, outside of Assembly or BASIC and other similarly limited languages. Java has plenty of more conventional/regular loop and control constructs.
I found labels to be sometimes useful in tests, to separate the usual setup, excercise and verify phases and group related statements. For example, using the BDD terminology:
#Test
public void should_Clear_Cached_Element() throws Exception {
given: {
elementStream = defaultStream();
elementStream.readElement();
Assume.assumeNotNull(elementStream.lastRead());
}
when:
elementStream.clearLast();
then:
assertThat(elementStream.lastRead()).isEmpty();
}
Your formatting choices may vary but the core idea is that labels, in this case, provide a noticeable distinction between the logical sections comprising your test, better than comments can. I think the Spock library just builds on this very feature to declare its test phases.
Personally whenever I need to use nested loops with the innermost one having to break out of all the parent loops, I just write everything in a method with a return statement when my condition is met, it's far more readable and logical.
Example Using method:
private static boolean exists(int[][] array, int searchFor) {
for (int[] nums : array) {
for (int num : nums) {
if (num == searchFor) {
return true;
}
}
}
return false;
}
Example Using label (less readable imo):
boolean exists = false;
existenceLoop:
for (int[] nums : array) {
for (int num : nums) {
if (num == searchFor) {
exists = true;
break existenceLoop;
}
}
}
return exists;