Difference between this to method - java

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!

Related

Infinite recursive call [duplicate]

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;
}

Tail recursive function still blowing the stack in Java

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;
}

Can the java compiler optimize loops to return early?

I'm working with an external library that decided to handle collections on its own. Not working with it or updating is outside my control. To work with elements of this third party "collection" it only returns iterators.
A question came up during a code review about having multiple returns in the code to gain performance. We all agree (within the team) the code is more readable with a single return, but some are worried about optimizations.
I'm aware premature optimization is bad. That is a topic for another day.
I believe the JIT compiler can handle this and skip the unneeded iterations, but could not find any info to back this up. Is JIT capable of such a thing?
A code sample of the issue at hand:
public void boolean contains(MyThings things, String valueToFind) {
Iterator<Thing> thingIterator = things.iterator();
boolean valueFound = false;
while(thingIterator.hasNext()) {
Thing thing = thingIterator.next();
if (valueToFind.equals(thing.getValue())) {
valueFound = true;
}
}
return valueFound;
}
VS
public void boolean contains(MyThings things, String valueToFind) {
Iterator<Thing> thingIterator = things.iterator();
while(thingIterator.hasNext()) {
Thing thing = thingIterator.next();
if (valueToFind.equals(thing.getValue())) {
return true;
}
}
return false;
}
We all agree the code is more readable with a single return.
Not really. This is just old school structured programming when functions were typically not kept small and the paradigms of keeping values immutable weren't popular yet.
Although subject to debate, there is nothing wrong with having very small methods (a handful of lines of code), which return at different points. For example, in recursive methods, you typically have at least one base case which returns immediately, and another one which returns the value returned by the recursive call.
Often you will find that creating an extra result variable, just to hold the return value, and then making sure no other part of the function overwrites the result, when you already know you can just return, just creates noise which makes it less readable not more. The reader has to deal with cognitive overload to see the result is not modified further down. During debugging this increases the pain even more.
I don't think your example is premature optimisation. It is a logical and critical part of your search algorithm. That is why you can break from loops, or in your case, just return the value. I don't think the JIT could realise that easily it should break out the loop. It doesn't know if you want to change the variable back to false if you find something else in the collection. (I don't think it is that smart to realise that valueFound doesn't change back to false).
In my opinion, your second example is not only more readable (the valueFound variable is just extra noise) but also faster, because it just returns when it does its job. The first example would be as fast if you put a break after setting valueFound = true. If you don't do this, and you have a million items to check, and the item you need is the first, you will be comparing all the others just for nothing.
Java compiler cannot do an optimization like that, because doing so in a general case would change the logic of the program.
Specifically, adding an early return would change the number of invocations of thingIterator.hasNext(), because your first code block continues iterating the collection to the end.
Java could potentially replace a break with an early return, but that would have any effect on the timing of the program.

Java nested if conditions or all condition in the same if

I have a loop iteration that contains many conditions in this form
if (a[k]<=x){
if(al[k+1]==y){
if(a[k+2]>=x){
}
}
}
Is better use Use the conditions in and in a single if in terms of performance??
if ((a[k]<=x) && (al[k+1]==y) && (a[k+2]>=x)){
}
As others have noted, aim for readability and don't prematurely optimize code. Measure performance and if you identify this snippet of code to be a bottleneck, then start to think more seriously about the issue.
Also as stated in comments, the performance will likely be identical in this situation. You might find different performance characteristics if you re-ordered the predicates. Something like:
if(B && A && C)
if calculating A is inexpensive and returns false 90% of the time, and calculating B is very expensive, you could instead write:
if(A && B && C)
but again, don't shoot from the hip! Aim first for readable code, and if your measurements identify a performance bottleneck, then consider the above.
Actually, the compiler is enough "smart" to compile the two codes to the same bytecode java but, if you want my opinion, the first is better (because reading a lot of if if if is annoying).
If you have many complex conditions in your loop like you say, consider moving them into small methods for improved readability.
// inside loop
if (isValid(x, y, k)) {
}
// use a less generic method name in your code
private boolean isValid(int x, int y, int k) {
return a[k]<=x && al[k+1]==y && a[k+2]>=x;
}
In case you are now worried that this will cause bad performance, there is a good chance that the JVM will inline these methods.

Should I avoid using Java Label Statements?

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;

Categories

Resources