Not using a while(true) loop - java

I recently asked a question over on code review, where I asked for someone to help optimise my code. I was told over there that using a while (true) was not useful, and I shouldn't do it. I then came over to look it through and I founf this exact question, about when to use one, and then answer said, you usually see one in games.
My question is when should I use one? And if I shouldn't use it now, what should I use instead?

Sometimes you need to make a decision to exit the loop in the middle of loop's body. Java offers loop control in two places - at the beginning of each iteration (while and for) and at the end of each iteration (do-while). You use while (true) with a break in these situations:
while (true) {
... // Do something
if (exitCondition) {
break;
}
... // Do something else
}

Related

Count how many list entries have a string property that ends with a particular char

I have an array list with some names inside it (first and last names). What I have to do is go through each "first name" and see how many times a character (which the user specifies) shows up at the end of every first name in the array list, and then print out the number of times that character showed up.
public int countFirstName(char c) {
int i = 0;
for (Name n : list) {
if (n.getFirstName().length() - 1 == c) {
i++;
}
}
return i;
}
That is the code I have. The problem is that the counter (i) doesn't add 1 even if there is a character that matches the end of the first name.
You're comparing the index of last character in the string to the required character, instead of the last character itself, which you can access with charAt:
String firstName = n.getFirstName()
if (firstName.charAt(firstName.length() - 1) == c) {
i++;
}
When you're setting out learning to code, there is a great value in using pencil and paper, or describing your algorithm ahead of time, in the language you think in. Most people that learn a foreign language start out by assembling a sentence in their native language, translating it to foreign, then speaking the foreign. Few, if any, learners of a foreign language are able to think in it natively
Coding is no different; all your life you've been speaking English and thinking in it. Now you're aiming to learn a different pattern of thinking, syntax, key words. This task will go a lot easier if you:
work out in high level natural language what you want to do first
write down the steps in clear and simple language, like a recipe
don't try to do too much at once
Had I been a tutor marking your program, id have been looking for something like this:
//method to count the number of list entries ending with a particular character
public int countFirstNamesEndingWith(char lookFor) {
//declare a variable to hold the count
int cnt = 0;
//iterate the list
for (Name n : list) {
//get the first name
String fn = n.getFirstName();
//get the last char of it
char lc = fn.charAt(fn.length() - 1);
//compare
if (lc == lookFor) {
cnt++;
}
}
return cnt;
}
Taking the bullet points in turn:
The comments serve as a high level description of what must be done. We write them aLL first, before even writing a single line of code. My course penalised uncommented code, and writing them first was a handy way of getting the requirement out of the way (they're a chore, right? Not always, but..) but also it is really easy to write a logic algorithm in high level language, then translate the steps into the language learning. I definitely think if you'd taken this approach you wouldn't have made the error you did, as it would have been clear that the code you wrote didn't implement the algorithm you'd have described earlier
Don't try to do too much in one line. Yes, I'm sure plenty of coders think it looks cool, or trick, or shows off what impressive coding smarts they have to pack a good 10 line algorithm into a single line of code that uses some obscure language features but one day it's highly likely that someone else is going to have to come along to maintain that code, improve it or change part of what it does - at that moment it's no longer cool, and it was never really a smart thing to do
Aominee, in their comment, actually gives us something like an example of this:
return (int)list.stream().filter(e -> e.charAt.length()-1)==c).count();
It's a one line implementation of a solution to your problem. Cool huh? Well, it has a bug* (for a start) but it's not the main thrust of my argument. At a more basic level: have you got any idea what it's doing? can you look at it and in 2 seconds tell me how it works?
It's quite an advanced language feature, it's trick for sure, but it might be a very poor solution because it's hard to understand, hard to maintain as a result, and does a lot while looking like a little- it only really makes sense if you're well versed in the language. This one line bundles up a facility that loops over your list, a feature that effectively has a tiny sub method that is called for every item in the list, and whose job is to calculate if the name ends with the sought char
It p's a brilliant feature, a cute example and it surely has its place in production java, but it's place is probably not here, in your learning exercise
Similarly, I'd go as far to say that this line of yours:
if (n.getFirstName().length() - 1 == c) {
Is approaching "doing too much" - I say this because it's where your logic broke down; you didn't write enough code to effectively implement the algorithm. You'd actually have to write even more code to implement this way:
if (n.getFirstName().charAt(n.getFirstName().length() - 1) == c) {
This is a right eyeful to load into your brain and understand. The accepted answer broke it down a bit by first getting the name into a temporary variable. That's a sensible optimisation. I broke it out another step by getting the last char into a temp variable. In a production system I probably wouldn't go that far, but this is your learning phase - try to minimise the number of operations each of your lines does. It will aid your understanding of your own code a great deal
If you do ever get a penchant for writing as much code as possible in as few chars, look at some code golf games here on the stack exchange network; the game is to abuse as many language features as possible to make really short, trick code.. pretty much every winner stands as a testament to condense that should never, ever be put into a production system maintained by normal coders who value their sanity
*the bug is it doesn't get the first name out of the Name object

Meaning of "for (;;)"? [duplicate]

This question already has answers here:
How does a for loop work, specifically for(;;)?
(6 answers)
Closed 9 years ago.
What is the meaning of for (;;)?
I found it in a certain base class and I cannot find explanation for in on the net.
Please also explain when and how to use this expression
It's an infinite loop. It has no initial condition, no increment and no end condition.
It's the same as
while(true) {
//do stuff
}
You can use it when you need something to be repeated continuously, until the application ends. But i would use the while version instead
It is read "for ever". the default for the condition is to evaluate to true.
When should you use it? If you don't want the loop to end (as is common in servers) or when the end condition is naturally known only in the middle of the loop, in which case you can use break:
for (;;) {
String in = get_input();
if (in.equals("end"))
break;
System.out.println("you entered " + in);
}
This is not the best example, though. You can do without the infinite loop here. For example:
for (String in = get_input(); !in.equals("end"); in = get_input()) {
System.out.println("you entered " + in);
}
It means an infinite loop. It is not considered a good practice to use this. Instead try while(true)
In some cases where you want to do a task again and again, sometimes forever. Such cases you use an infinite loop. This can be done in many ways. Notable ones are,
Using while,
while(true)
{
// Task you want to repeat
}
Using for,
for(;;)
{
// Task you want to repeat
}
Note : You might have to be very much careful while implementing infinite loops as there exists a possibility of same problem recurring. It is a good practice to catch the exception and retry for some time and if still problem persist, break from the loop.

Is it bad practice to use break to exit a loop in Java? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I was wondering if it is a "bad practice" to use a break statement to exit a loop instead of fulfilling the loop condition?
I do not have enough insight in Java and the JVM to know how a loop is handled, so I was wondering if I was overlooking something critical by doing so.
The focus of this question: is there a specific performance overhead?
Good lord no. Sometimes there is a possibility that something can occur in the loop that satisfies the overall requirement, without satisfying the logical loop condition. In that case, break is used, to stop you cycling around a loop pointlessly.
Example
String item;
for(int x = 0; x < 10; x++)
{
// Linear search.
if(array[x].equals("Item I am looking for"))
{
//you've found the item. Let's stop.
item = array[x];
break;
}
}
What makes more sense in this example. Continue looping to 10 every time, even after you've found it, or loop until you find the item and stop? Or to put it into real world terms; when you find your keys, do you keep looking?
Edit in response to comment
Why not set x to 11 to break the loop? It's pointless. We've got break! Unless your code is making the assumption that x is definitely larger than 10 later on (and it probably shouldn't be) then you're fine just using break.
Edit for the sake of completeness
There are definitely other ways to simulate break. For example, adding extra logic to your termination condition in your loop. Saying that it is either loop pointlessly or use break isn't fair. As pointed out, a while loop can often achieve similar functionality. For example, following the above example..
while(x < 10 && item == null)
{
if(array[x].equals("Item I am looking for"))
{
item = array[x];
}
x++;
}
Using break simply means you can achieve this functionality with a for loop. It also means you don't have to keep adding in conditions into your termination logic, whenever you want the loop to behave differently. For example.
for(int x = 0; x < 10; x++)
{
if(array[x].equals("Something that will make me want to cancel"))
{
break;
}
else if(array[x].equals("Something else that will make me want to cancel"))
{
break;
}
else if(array[x].equals("This is what I want"))
{
item = array[x];
}
}
Rather than a while loop with a termination condition that looks like this:
while(x < 10 && !array[x].equals("Something that will make me want to cancel") &&
!array[x].equals("Something else that will make me want to cancel"))
Using break, just as practically any other language feature, can be a bad practice, within a specific context, where you are clearly misusing it. But some very important idioms cannot be coded without it, or at least would result in far less readable code. In those cases, break is the way to go.
In other words, don't listen to any blanket, unqualified advice—about break or anything else. It is not once that I've seen code totally emaciated just to literally enforce a "good practice".
Regarding your concern about performance overhead, there is absolutely none. At the bytecode level there are no explicit loop constructs anyway: all flow control is implemented in terms of conditional jumps.
The JLS specifies a break is an abnormal termination of a loop. However, just because it is considered abnormal does not mean that it is not used in many different code examples, projects, products, space shuttles, etc. The JVM specification does not state either an existence or absence of a performance loss, though it is clear code execution will continue after the loop.
However, code readability can suffer with odd breaks. If you're sticking a break in a complex if statement surrounded by side effects and odd cleanup code, with possibly a multilevel break with a label(or worse, with a strange set of exit conditions one after the other), it's not going to be easy to read for anyone.
If you want to break your loop by forcing the iteration variable to be outside the iteration range, or by otherwise introducing a not-necessarily-direct way of exiting, it's less readable than break.
However, looping extra times in an empty manner is almost always bad practice as it takes extra iterations and may be unclear.
In my opinion a For loop should be used when a fixed amount of iterations will be done and they won't be stopped before every iteration has been completed. In the other case where you want to quit earlier I prefer to use a While loop. Even if you read those two little words it seems more logical. Some examples:
for (int i=0;i<10;i++) {
System.out.println(i);
}
When I read this code quickly I will know for sure it will print out 10 lines and then go on.
for (int i=0;i<10;i++) {
if (someCondition) break;
System.out.println(i);
}
This one is already less clear to me. Why would you first state you will take 10 iterations, but then inside the loop add some extra conditions to stop sooner?
I prefer the previous example written in this way (even when it's a little more verbose, but that's only with 1 line more):
int i=0;
while (i<10 && !someCondition) {
System.out.println(i);
i++;
}
Everyone who will read this code will see immediatly that there is an extra condition that might terminate the loop earlier.
Ofcourse in very small loops you can always discuss that every programmer will notice the break statement. But I can tell from my own experience that in larger loops those breaks can be overseen. (And that brings us to another topic to start splitting up code in smaller chunks)
Using break in loops can be perfectly legitimate and it can even be the only way to solve some problems.
However, it's bad reputation comes from the fact that new programmers usually abuse it, leading to confusing code, especially by using break to stop the loop in conditions that could have been written in the loop condition statement in the first place.
No, it is not a bad practice to break out of a loop when if certain desired condition is reached(like a match is found). Many times, you may want to stop iterations because you have already achieved what you want, and there is no point iterating further. But, be careful to make sure you are not accidentally missing something or breaking out when not required.
This can also add to performance improvement if you break the loop, instead of iterating over thousands of records even if the purpose of the loop is complete(i.e. may be to match required record is already done).
Example :
for (int j = 0; j < type.size(); j++) {
if (condition) {
// do stuff after which you want
break; // stop further iteration
}
}
It isn't bad practice, but it can make code less readable. One useful refactoring to work around this is to move the loop to a separate method, and then use a return statement instead of a break, for example this (example lifted from #Chris's answer):
String item;
for(int x = 0; x < 10; x++)
{
// Linear search.
if(array[x].equals("Item I am looking for"))
{
//you've found the item. Let's stop.
item = array[x];
break;
}
}
can be refactored (using extract method) to this:
public String searchForItem(String itemIamLookingFor)
{
for(int x = 0; x < 10; x++)
{
if(array[x].equals(itemIamLookingFor))
{
return array[x];
}
}
}
Which when called from the surrounding code can prove to be more readable.
There are a number of common situations for which break is the most natural way to express the algorithm. They are called "loop-and-a-half" constructs; the paradigm example is
while (true) {
item = stream.next();
if (item == EOF)
break;
process(item);
}
If you can't use break for this you have to repeat yourself instead:
item = stream.next();
while (item != EOF) {
process(item);
item = stream.next();
}
It is generally agreed that this is worse.
Similarly, for continue, there is a common pattern that looks like this:
for (item in list) {
if (ignore_p(item))
continue;
if (trivial_p(item)) {
process_trivial(item);
continue;
}
process_complicated(item);
}
This is often more readable than the alternative with chained else if, particularly when process_complicated is more than just one function call.
Further reading: Loop Exits and Structured Programming:
Reopening the Debate
If you start to do something like this, then I would say it starts to get a bit strange and you're better off moving it to a seperate method that returns a result upon the matchedCondition.
boolean matched = false;
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
if(matchedCondition) {
matched = true;
break;
}
}
if(matched) {
break;
}
}
To elaborate on how to clean up the above code, you can refactor, moving the code to a function that returns instead of using breaks. This is in general, better dealing with complex/messy breaks.
public boolean matches()
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
if(matchedCondition) {
return true;
}
}
}
return false;
}
However for something simple like my below example. By all means use break!
for(int i = 0; i < 10; i++) {
if(wereDoneHere()) { // we're done, break.
break;
}
}
And changing the conditions, in the above case i, and j's value, you would just make the code really hard to read. Also there could be a case where the upper limits (10 in the example) are variables so then it would be even harder to guess what value to set it to in order to exit the loop. You could of course just set i and j to Integer.MAX_VALUE, but I think you can see this starts to get messy very quickly. :)
No, it is not a bad practice. It is the most easiest and efficient way.
While its not bad practice to use break and there are many excellent uses for it, it should not be all you rely upon. Almost any use of a break can be written into the loop condition. Code is far more readable when real conditions are used, but in the case of a long-running or infinite loop, breaks make perfect sense. They also make sense when searching for data, as shown above.
If you know in advance where the loop will have to stop, it will probably improve code readability to state the condition in the for, while, or `do-while loop.
Otherwise, that's the exact use case for break.
break and continue breaks the readability for the reader, although it's often useful.
Not as much as "goto" concept, but almost.
Besides, if you take some new languages like Scala (inspired by Java and functional programming languages like Ocaml), you will notice that break and continue simply disappeared.
Especially in functional programming, this style of code is avoided:
Why scala doesn't support break and continue?
To sum up: break and continueare widely used in Java for an imperative style, but for any coders that used to practice functional programming, it might be.. weird.

Java - Turning the for-loop counter back based on a conditional

The following is part of the code for my college assignment.
else if (!codeList.contains(userCode)) {
i--; // i is the counter for the for-loop
}
else if (userQuantity[i]==0) {
i--;
}
The first part makes sure that if the user enters the wrong code, the counter i does not increment 1, or rather, it subtracts 1 from the recently incremented counter. This part works fine.
The second part however is what I seem to be having problems with. userQuantity[] is an int array and it has to be an array. This does not seem to do anything to the code. Even if 0 is entered for the quantity, it still incrememnts the counter which is not desireable.
I should explain, to avoid confusion, that this is an infinite for-loop (with a break statement). The reason I am doing a for-loop is because I am required to. Is it because of my for-loop that the condition isn't working or am I doing something completely wrong with it?
This is for my college assignment so I would appreciate answers with explanation and not just quick-fixes. If you need me to explain, let me know please.
Although it's not strictly illegal in Java, it's not a good idea to change the value of the for loop control variable from within the loop. (Such modification is illegal in some other languages.)
By changing the loop iteration variable within the loop, you're messing with the implicit assumptions offered by your use of a for loop. For example, if a reader sees:
for (int i = 0; i < 10; i++) {
// ...
}
the reader will rightfully assume that the loop is intended to execute exactly 10 times (or, no more than 10 if there is a break in there). However, if you go changing the value of i within the loop, this assumption is no longer valid.
If you must change the value of the counter, I would suggest writing this as a while loop instead:
int i = 0;
while (i < 10) {
// ...
i++;
}
along with a comment that explains why you are changing i within the loop and what it means to do so.
This is very bad practice. Change the for loop to a while loop and only increment if
codeList.contains(userCode)==true or userQuantity[i]!=0.
I should explain, to avoid confusion, that this is an infinite for-loop (with a break statement). The reason I am doing a for-loop is because I am required to. Is it because of my for-loop that the condition isn't working or am I doing something completely wrong with it?
I have a feeling that you are misunderstanding the requirements (e.g. you are not required to use a for loop), or that there is a mistake in your thinking; i.e. there is a simpler solution that doesn't involve the counter going backwards.
(It is surprising that a programming exercise would require you to write code that most experienced Java programmers would agree is bad code. The simple explanation is that it is not.)
Either way:
Changing the loop variable in a for loop is bad practice, for the reasons described by Greg.
The idea of an "infinite for loop" is really strange. The following is legal Java ...
for (int i = 0; true; i++) {
...
}
but the idiomatic way to write it is:
int i = 0;
while (true) {
...
i++; // ... at the appropriate point / points
}
... which in most cases means that you don't need to make the variable go backwards at all.

For loop with no parameters in Java

I am looking at somebody else's code and I found this piece of code:
for (;;) {
I'm not a Java expert; what is this line of code doing?
At first, I thought it would be creating an infinite loop, but in the very SAME class this programmer uses
while(true)
Which (correct me if I'm wrong) IS an infinite loop. Are these two identical? Why would somebody change their method to repeat the same process?
Any insight would help,
Thanks!
Remember the three clauses of the for() are [1] initialization [2] termination and [3] increment. Since the termination clause is empty the loop never terminates. This is directly taken from C syntax.
Those two lines would have the same effect. I can't think of a good reason to use the first one unless you like to confuse people. I guess it's less characters.
they are entirely the same the only real difference would be either preference (the for construct can be typed marginally faster)
or the for indicates that is is some iteration that is broken out of by a break or return and a while loop indicates a repeating section of the same thing until a meaningful result appears

Categories

Resources