Simple loop performance issue - java

Say I have a simple PHP loop like this one
// Bad example
$array = array('apple','banana','cucumber');
for ($i = 1; $i < count($array); $i++) {
echo $array[$i];
}
I know this is a bad practice. It's better not using count() inside a loop.
// Nice example
$array = array('apple','banana','cucumber');
$limit = count($array);
for ($i = 1; $i < $limit; $i++) {
// do something...
}
In Java, I would do it this way
// Bad example?
String[] array = {"apple","banana","cucumber"};
for(int i = 0; i < array.length; i++){
System.out.println(array[i]);
}
Question: Isn't this above a bad practice too? Or it is just the same as the example below?
// Nice example?
String[] array = {"apple","banana","cucumber"};
int limit = array.length;
for(int i = 0; i < limit; i++){
System.out.println(array[i]);
}

Any decent compiler/interpreter should automatically optimise the first example to match the second (semantically speaking anyway, if not exactly literally), and probably the third to match the fourth. It's known as a loop invariant optimisation, where the compiler recognises that an entity (variable, expression, etc) does not vary within the loop (i.e. is invariant) and removes it to outside the loop (loosely speaking).
It's not bad practice at all anymore, if it ever was.

The "bad" examples you use are not equivalent, and thus are not comparable - even if they seem so on the surface. Using this description:
for (initialization; termination; increment) {
statement(s)
}
(which is descriptive of both PHP and java loops), the initialization statement is executed once, at the start of the loop. The termination statement and the increment are executed for each iteration of the loop.
The reason it is bad practice to use PHP's count in the termination statement is that, for each iteration, the count function call occurs. In your Java example, array.length is not a function call but a reference to a public member. Therefore, the termination statements used in your examples are not equivalent behavior. We expect a function call to be more costly than a property reference.
It is bad practice to place a function call (or call a property that masks a function) in the termination statement of a for loop in any language which has the described loop mechanics. That's what makes the PHP example "bad", and it would be equally bad if you used a count-type function in Java for loop's termination statement. The real question, then, is whether Java's Array.length does indeed mask a function call - the answer to that is "no" (see the potential duplicate question, and/or check out http://leepoint.net/notes-java/data/arrays/arrays.html)

The main difference is that count() is a function whereas array.length is a property and therefore not different from a limit variable.

They are not the same, in the Java "nice example" you are not calculating the length of the array every time. Instead, you are storing that in the limit variable and using that to stop the calculation instead of the result of calling the length function on the array every iteration through the for loop.
EDIT: Both of the things that you thought were "bad practice" are bad practice and the "nice examples" are the more efficient ways (at least in theory). But it is true that in implementation there will not be any noticeable difference.

In java this doesn't matter an array has this attribute as a constant (public final int).
The difference is in java arrays have a fixed size and can not grow so there would be no need to count the elements every time to access length.

Related

Do While Loops Versus For Loops in Java for Counting

When it comes to counting, should a do-while loop be used, or a for loop? Because this:
class Main {
public static void main(String[] args) {
int times = 1;
do {
System.out.println("I have printed " + times + " times.");
times++;
} while (times < 6);
}
}
Seems to do the exact same thing as this:
class Main {
public static void main(String[] args) {
for (int times = 1; times < 6; times++) {
System.out.println("I have printed " + times + " times.");
}
}
}
Is it a difference in speed? Preference? Situation? Personal quirks? Some kind of "Java social taboo"? I have no idea. Either seem to be able to be used for effective counting, just that one takes a lot more. And both print the exact same thing.
System.out.println("Many thanks!!");
You're right, these do the same thing (except one starts counting at 0 and the other at 1, but that's just an implementation detail). If your program knows in advance (before the loop starts) how many times you want the loop to iterate, most Java developers will tell you to go with a for loop. That's what it's designed for.
A while loop or do while loop is better suited for situations where you're looking for a specific value or condition before you exit the loop. (Something like count >= 10 or userInput.equals("N"). Anything that evaluates to a boolean True/False value.)
When faced with these kind of dilemmas, aim for readability and familiarity. You should not concern yourself with micro-optimizations. Focus on readability and clearly conveying you intent. Do as other do in similar situation.
Like #Bill-The-Lizard said, while loop suggests to the reader of your code that you opted for it, because you're not counting, but repeating until a condition is met. At least once - otherwise you'd have chosen while(...){ } loop.
In other words, for, do {} while() and while() { } generally work the same. But one may better convey you intent in your particular piece of logic.
I think it's more of a readability and syntactic sugar. This while condition
while (condition)
can also be written as
for (; condition; )
but obviously the first one looks lot better and is more readable.
It depends on the programmer's choice when to use for loop or do while loop but the general practice followed by most of the programmers is
For loop
When you know that the loop will execute a predefined number of times(general practice since you can also use for(;true;) which loops forever).
For example a loop which runs 10 times or n number of times where n is a variable
for(int i = 0; i < n; i++) {
//Do something
}
While loop
When you know that the loop should terminate after the evaluation of a specific condition as true or else you want the loop to run forever (like while(true)) and check the break conditions inside the while loop.
Also the while loop is preferred when you can't figure out the conditions in the first place and start with while(true) but once you write code inside the loop you get good understanding of what's happening and get the idea about which conditions to check thus when to exit the loop.
For example
while(x != 0) {
//Do something;
x--;
}
while(true) {
// some code to execute on which the condition depends
if(condition is true) {
break;
}
}
Do while loop
Do while loop is similar to the while loop but with a small difference. That is it allows the first iteration to happen without checking the condition(specified in the while statement, but you can still evaluate the condition inside the block(curly braces)).
By convention most Java developers use for loops. Effective Java recommends for loops instead of while loops because the loop variable can use a tighter scope which reduces bugs. http://www.corejavaguru.com/effective-java/items/45
Recent versions of Java also allow the following
IntStream.range(0, 6).forEach(
i -> System.out.println("I have printed " + i + " times.")
);
Beyond personal preferences, this one has the advantage that the index is maintained by the runtime and there is no need for the programmer to ++i

Why is it bad to change for loop counter in Java?

I often heard that it's bad to modify the loop counter in the body of a for loop. The following (bad) example shows what I am talking about.
for (int i=0; i<10; i++) {
i++;
}
I know that this would be allowed within while loops but could anybody explain why this is a bad practice in Java resp. even a problem in any programming language.
Two reasons why this is bad:
Readability. for( a; b; c ) { d; } is a shorthand for a; while( b ) { d; c; } explicitly for the case where you are iterating over a list. It is not strictly needed in the language. The whole point of having it is to imply intent: "I want to iterate over an entire list" or "I want to iterate over part of a list in sequence, then abort when I find something" at most.
If you add an additional increment, that will surprise other people encountering your code. If your c above says ++x or whatever, people will simply assume it loops over all items, just to then find "surprise! not always!".
OTOH, if you use a while loop, people only see the condition, and are alerted that this will be a more complex loop where the increment will not be constant.
Optimiziation. Given the above statement of intent, some optimizers will generate different code for a for statement than a while statement. Although none of them should generate wrong code, they might apply an optimization that has worse performance characteristics for non-sequential access than for sequential access.
And by "worse performance characteristics" I mean they may tell the CPU to cache the wrong code path and slow down your execution by a fraction of a cycle because data may have to be loaded into the CPU again after having needlessly been flushed.
Just look at what happens with this code:
1 for (int i=0; i<10; i++) {
2 i++;
3 }
Initially line 1 i=0.
Line 2 increments i, which now equals 1.
End of loop, so i++ takes effect, now i=2.
And so on ...
So if you really wanted to do something like this, you could have wrote it like:
for (int i=0; i<10; i+=2) {
}
Which gets the same result. It's not necessarily bad code, but it doesn't make sense to code like that, and it's very hard to troubleshoot.
Mainly because most of the programmers use it that way, so it is more readable for everyone as mentioned by #AntonH.
Side note: trying as in other language (like C if memory serves) to write:
for(int i =0; i< 10; i){
printf("%d", i);
i++;
}
This code compiles and run. In Java, the equivalent:
for(int i =0; i< 10; i){
System.out.println("%d", i);
i++;
}
Edited thanks to #David Wallace:This yields a compilation error, it is mandatory to have an assignement in the statement part of the for loop.

Initialization statement

I'm reading a Java book and I came across an interesting for loop. It looks like this:
for(; (j>0) && (tmp < a[j-1]); j--)
I understand that (j>0) && (tmp < a[j-1]) is the condition check and j-- is the decrease of the variable. However, I don't get where's the initialization statement.
There is no initialization statement in your example. It's optional.
j is probably declared and initialized before the loop.
Normally, you would initialize j in the first statement in the for loop (which is empty here) since it is a looping index and is usually only used inside the loop. Also the standard syntax for Java for loops is for( initialization; termination condition; increment), but the language only enforces that there be three statements (with the middle one being a boolean expression) , so you can have three empty statements for(;;) which creates an infinite loop or you could put some other statement in there (except for the middle expression where a boolean expression is expected) like for(System.out.println("I was supposed to initialize here"); false && true; logger.log("Nope.")). OF course, you shouldn't do that, but it is legal.
Note: Some statements would be illegal if put in place of the third statement as well, like variable declarations, since it is executed at the end of each iteration (see this for more on legal for loop syntax)
I like to think of for loops as a shorthand for a common form of the while loop, where you want to loop a number of times:
int i= 0; // Initialization
while (i< max){ // termination
// Do stuff
i++; // increment
}
which is helpful for understanding what it does with these statements.
for(initialization; condition; increment)
None of them are a must to declare a for loop. You can have a for loop like for(;;) if you want. It will compile without any errors.
According to your question j have been already initialized some where. Therefore it is perfectly fine.

Array iteration with static final limits

I have an array:
final int[] exampleArray = new int[ID_DATA_ARRAY_SIZE];
And I can iterate that array several ways, for example:
Way 1:
for (int i = 0; i < exampleArray.length; i++) {
// code where I use 'i' index
}
Way 2:
for (int i = 0; i < ID_DATA_ARRAY_SIZE; i++) {
// code where I use 'i' index
}
Which way is better? Are there any other better ways to do it?
If you don't need i for anything else than extracting the element, then the enhanced for loop looks a bit nicer:
for(int element : exampleArray) {
//code that uses element
}
If you are using i for both accessing the array, and something else, then I would argue Way 1 is best:
for (int i = 0; i < exampleArray.length; i++) {
// code where I use 'i' index
}
The reason is that the next time someone looks at a code, the person will immediately see that you are iterating to the length of the array. If you go for way 2 (using a constant), the reader might wonder if that constant really is the length of your array.
Tackling both performance, and code readability, way 2 is better.
Rated by performance, by using exampleArray.length you are calling upon a "member" variable which requires additional java bytecode to request when compared to calling a "local" variable. But, the difference in performance is extremely minuscule and you would never notice it unless you were making an extreme amount of calculations.
Rated by readability, ID_DATA_ARRAY_SIZE lays out your intent for whomever is reading, which is more important than it may seem. Yet, too many programmers lay out nonsensical or ambiguous variable names, and it makes reading their code lacking in naturalness. Naming variables and functions in a way that makes sense to our minds in an organic way makes the code much simpler to deal with for yourself in the future, and anyone else, making it a good practice.
The fundamental difference in the two approaches, I see is as below:
In Way 1: you use the constant exampleArray.length in the loop condition
In Way 2: you use the constant ID_DATA_ARRAY_SIZE in the loop condition
Obviously way 2 is superior in terms of performance.
This is because you are accessing a constant rather than access member variable of exampleArray object. This advantage is realized in every iteration of the for loop where the value of length member is accessed.
see it is all about personal taste which way you wanna do but whenever you are working with array better to check null for the array and then do your stuff

i++ or i-- in a for loop? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
While writing a for loop where both start and end conditions are known, which way is better? Let's say I have to iterate a loop for addition of an array elements of size 5. In this case which one of the following would be more efficient as far as execution time is concerned? Which one will give better performance?
for (i = 0; i < 5; i++)
{
/* logic */
}
OR
for (i = 4; i >= 0; i--)
{
/* logic */
}
Apart from the difficulty in writing i = 5 - 1; that is i = 4;, are there any other considerations?
It's usually recommended to concentrate on making code as clear and as logical as possible, without worrying about micro-optimizations or other factors. In your case, the first one is the better choice, since most programmers are more used to traverse an array in that order.
Both versions will have the same result (given that they're implemented correctly) and will have exactly the same run time.
EDIT: #Zane mentioned in a comment that looping backwards to zero was faster some time ago. It was, the reason for it was that comparing a variable to zero was faster. Given that computers were much much slower those days, such optimizations were encouraged. Those days are indeed over...
There is something wrong in your code.
The first loop is fine but the second while never execute:
it runs for 0 times. It should be
for(i=4;i>=0;i--){}
Besides, if you ask which is better, its your choice, with which one you are comfortable with.
For me, I feel the first one to be more comfortable.
In most cases it wouldn't matter, however there are some situations where non-obvious side-effects might interfere.
Consider a loop:
for(int i = 0; i < strlen(str); i++) {/* do stuff on i-th elem */}.
Here on each iteration the strlen(str) will be reevaluated (unless optimized by compiler) even though it's completely unnecessary; the programmer most likely didn't even consider this.
It might be worth replacing the loop with:
for(int i = strlen(str); i > 0; i--) {/* do stuff on i-th elem */}.
Here length of the string will be evaluated only once.
Of course, in the first loop the problem can be avoided as well by using additional variable to hold the length of the string but it's just an unnecessary noise, not related to the program logic.
The most obvious answer is: which one has the semantics you want? They
visit the objects in a different order.
As a general rule, if there are no other considerations, people expect
ascending order, and this is what you should use when visiting objects.
In C++, it is far more idiomatic to use iterators for this. Normal
iterators visit in ascending order, reverse iterators in descending. If
you don't explicitly need descending, you should use normal iterators.
This is what people expect, and when you do use reverse iterators, the
first thing a reader will ask is why. Also, I haven't measured, but it
wouldn't surprise me if normal iterators were faster than reverse
iterators. In Java, iterators are also idiomatic, and you don't have
reverse iterators.
If I do need descending order when visiting, I'll use a while loop (if I
don't have reverse iterators, which do it for me); I find something
like:
int index = numberOfElements;
while ( index != 0 ) {
-- index;
// ...
}
far more readable (and easier to get right) than any of the
alternatives.
If you're not visiting objects, but just counting, descending order
seems more natural to me: the control variable contains the number of
times left. And since the count is never used as an index, there's no
problem with the fact that it would be one off as an index, and you can
use a traditional for.
for ( int count = numberOfTimes; count != 0; -- count ) {
// ...
}
But it's really a question of style; I've seen a lot of ascending loops
for this as well.
The incremental for loop or decremented for loop is opted based on the way you want to use the counter variable or how good it looks
if you are accessing some array in ascending order, decremented for loop will be used
for (i = 0; i < 5; i++)
{
arr[i];
}
if you are accessing some array or list in descending order, incremental for loop is used
for (i = 5; i > 0 ; i--)
{
arr[i-1];
}
if the counter number has no significance for the value that is accessed, then readability of code is looked on. And incremental for loop looks more eye pleasing.
I would say the loop with i++ is easier to understand. Also, going backwards can make a suboptimal use of the processor cache, but usually compilers/ virtual machines are smarter than that.
I believe most programmers would be able to understand your code more quickly using the first method (i++). Unless you have the need to process an array in reverse I would stick with your first method. As for performance, I believe there would be little or no benefit to either solution.
Also you may want to consider using the for..each (enhanced for) syntax, which is quite tidier.
int[] x = {1,2,3,4,5};
for(int y: x){
System.out.println(y);
}

Categories