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
Related
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
}
So the context is, I have a CS project where input is taken in either word or sentence form, and then it is translated to what The Swedish Chef from The Muppets would say. I decided to take the input as one line of string, and send that line into a parser, which in turn would build an array out of translations of the input's letters. The conditions for what gets changed are defined within. the current error I am getting: (while using "INPUT" as input)
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 3, Size: 1
at java.util.ArrayList.rangeCheckForAdd(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
at SwedishTranslator.parseString(SwedishTranslator.java:62)
at SwedishTranslator.main(SwedishTranslator.java:12)
Currently it is supposed to just print the array, I wanted to worry about formatting after the fact.
The code:
Sorry for the walls of text but I can't find where the issue is exactly and I figured I would give it a shot here. Thanks in advance.
ind<=in.length() goes one step too far.
Use ind < in.length() or ind <= in.length() - 1
The error arrises on line 62 which I assume is in your big if else section.
Within there you have several ind++ calls. This increments the pointer you use in the loop. So if your code must go through several of these statements it will go beyond the array index.
Additionally you have an issue in the for loop as joval mentioned
Edit
The ++ unary operator increments the variable (-- decrements). Placing the ++ after the variable name (x++) will increment before evaluation, where ++x will increment after evaluation.
This is a common test question for CS students so I suggest you do some more research and practice regarding the operator.
You're making a couple of really understandable beginner mistakes here. Instead of explicitly fixing your code, I'll tell you about a couple of things that, if considered while reviewing and editing your code, will also fix your problem.
The documentation for String.charAt http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#charAt(int) throws an error when you attempt to access out-of-bounds items in the String. Make sure that you check that you're not attempting to look beyond the length of the String before you go calling charAt all willy-nilly! If you're currently "considering" the 'T' in "INPUT" and you go trying to look at the next two characters, Java will complain.
Second, and this is more of a general thing (though it does need to be fixed in your code above); the '++' operator doesn't do what you appear to think it actually does. When you do this: in.charAt(ind++)=='H', you may think you're just checking on the value at the next index, but you're actually advancing the index at the same time! The '++' operator is very handy, but it has a side affect that trips up a lot of beginners: it assigns itself + 1 to itself! That means that if you're on the 'I' in "INPUT" and somewhere within your loop you call ind++ once, you'll be on 'P' at the next iteration of your loop! When you see '++' remember that you're changing the value of the variable.
Good luck!
I have a .toUpperCase() happening in a tight loop and have profiled and shown it is impacting application performance. Annoying thing is it's being called on strings already in capital letters. I'm considering just dropping the call to .toUpperCase() but this makes my code less safe for future use.
This level of Java performance optimization is past my experience thus far. Is there any way to do a pre-compilation, set an annotation, etc. to skip the call to toUpperCase on already upper case strings?
What you need to do if you can is call .toUpperCase() on the string once, and store it so that when you go through the loop you won't have to do it each time.
I don't believe there is a pre-compilation situation - you can't know in advance what data the code will be handling. If anyone can correct me on this, it's be pretty awesome.
If you post some example code, I'd be able to help a lot more - it really depends on what kind of access you have to the data before you get to the loop. If your loop is actually doing the data access (e.g., reading from a file) and you don't have control over where those files come from, your hands are a lot more tied than if the data is hardcoded.
Any many cases there's an easy answer, but in some, there's not much you can do.
You can try equalsIgnoreCase, too. It doesn't make a new string.
No you cannot do this using an annotation or pre-compilation because your input is given during the runtime and the annotation and pre-compilation are compile time constructions.
If you would have known the input in advance then you could simply convert it to uppercase before running the application, i.e. before you compile your application.
Note that there are many ways to optimize string handling but without more information we cannot give you any tailor made solution.
You can write a simple function isUpperCase(String) and call it before calling toUpperCase():
if (!isUpperCase(s)) {
s = s.toUpperCase()
}
It might be not significantly faster but at least this way less garbage will be created. If a majority of the strings in your input are already upper case this is very valid optimization.
isUpperCase function will look roughly like this:
boolean isUpperCase(String s) {
for (int i = 0; i < s.length; i++) {
if (Character.isLowerCase(s.charAt(i)) {
return false;
}
}
return true;
}
you need to do an if statement that conditions those letters out of it. the ideas good just have a condition. Then work with ascii codes so convert it using (int) then find the ascii numbers for uppercase which i have no idea what it is, and then continue saying if ascii whatever is true then ignore this section or if its for specific letters in a line then ignore it for charAt(i)
sorry its a rough explanation
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.
I have a code something like this
Enumeration parameterEnum = request.getParameterNames()
while(parameterEnum.hasMoreElements()){}
what is the difference if I change it from a while statement into an if statement?
If you change it to an if it will either execute once or not at all - a while statement will execute indefinitely until ParameterEnum.hasMoreElements() returns false.
If I understand what you are asking, the current code would keep running whatever is in the brackets until there are not elements. This assumes that what is in the brackets takes off elements. As literally shown above, it is an infinite loop and will never end.
If you convert the while to an if, then what is in the brackets will run only once.
If Request.getParameterNames() returns an "empty" whatever-it-is, then neither case will do anything.
The if will be much, much faster!!! its complexity is O(1) and that of while's is O(N)!!!
So, the larger the input is, the better it is to use an if instead of a while ;-)
You might be thinking of a for statement, not an if.
if(ParameterEnum.hasMoreElements()) {}
The if will only run once
while(ParameterEnum.hasMoreElements()) {}
the while will run continuously, unless you increment the enum.
the other option is for:
for(Enumeration paramEnum = Request.getParameterNames();
parameEnum.hasMoreElements();) {}
this is similar to the while, and will run for as long as the hasMoreElements() method returns true, so incrementing the enum with nextElement() is important.