Java for-loop best practice - java

What is the best way to loop through an array when you need the index?
Option 1:
int len = array.length;
for (int i = 0; i < len; ++i) {
array[i] = foo(i);
}
Option 2:
for (int i = 0; i < array.length; i++) {
array[i] = foo(i);
}
Or, does it not matter? Or is there a better way to do it?
Just to point out the differences: In one case, the length of the array is evaluated as part of the test in the loop, although the compiler should normally optimize that.
Secondly, is ++i any different here from i++? I definitely prefer ++i if it is C++ but am not sure for Java.

i++ vs ++i does not matter in this particular case. While C masters will tell you to store array.length in a variable, modern optimizing compilers make that unnecessary in this case as long as the length does not change in the loop. If you're really concerned you can benchmark both, but since .length doesn't actually need to traverse the entire array each time you'll be OK.

Generally those two methods are equivalent. You should note that in
for (int i = 0 ; i < foo() ; i++) {
...
}
the foo() is called once before each iteration (as opposed to only once before the first iteration), so you might want to take this into account for more complicated situations by perhaps doing something like
int n = foo();
for (int i = 0 ; i < n ; i++) {
...
}
which is analogous to your Option 1. So I would say Option 1 is certainly the safer of the two, but most of the time it should not make a significant difference which you use.
As for your second question: ++i first increments your variable and then retrieves it's value, i++ first retrieves the value and then increments. Just try these two pieces of code:
int i = 0;
System.out.println(++i);
------------------------
int i = 0;
System.out.println(i++);
The first prints 1 but the second prints 0. Of course when ++i and i++ are alone it makes no difference.

for whether to use "array.length" in for loop:
Generally the compiler will do some optimization, as a result it is equivalent to using a variable in the for loop
for "i++" and "++i"
In C++, ++i is preferred and more efficient, but in Java, they are equivalent in this case.

In addition to arshaji response I wanted to know if there was a performance benefit of using size() in a loop vs storing it in advance. I believe the result show that the compiler does optimize things and accessing the length of a list is the same as accessing a variable ( I was worried that the fact it had to go through a function would slow down things).
Here is the time it takes for those two for different method of loop:
for(long i = 0 ; i < mylist.size(); i++){}
VS
for(long i = 0 ; i < 10_000_000; i++){}
Here is the result for a list of ten million elems:
fixed length:
,162,157,151,157,156,159,157,149,150,170,158,153,152,158,151,151,156,156,151,153
getSize:
,164,156,159,154,151,160,162,152,154,152,151,149,168,156,152,150,157,150,156,157
import java.util.ArrayList;
import java.util.List;
public class Main {
final static int LENGTH_SAMPLE = 20;
final static long LENGTH = 10_000_000;
public static void main(String[] args) {
List<Long> mylist = new ArrayList<>();
for(long i = 0 ; i < LENGTH; i++){
mylist.add(i);
}
System.out.println("fixed length:");
for(int i = 0 ; i < LENGTH_SAMPLE; i++){
System.out.printf("," + fixedSize(mylist));
}
System.out.println("");
System.out.println("getSize:");
for(int i = 0 ; i < LENGTH_SAMPLE; i++){
System.out.printf("," + fctSize(mylist));
}
}
private static long fixedSize(List list){
long start = System.currentTimeMillis();
for(long i = 0 ; i < LENGTH; i++){
System.currentTimeMillis();
}
return System.currentTimeMillis() - start;
}
private static long fctSize(List list){
long start = System.currentTimeMillis();
for(long i = 0 ; i < list.size(); i++){
System.currentTimeMillis();
}
return System.currentTimeMillis() - start;
}
}

Related

Loop unrolling in Scala vs Java

Does loop unrolling works for loops where iteration count is determined during runtime? E.g. will the inner loop will be considered for unrolling in this code:
for(int j = 0; j < HUGE_NUMBER; j++) {
int N = getCount(); // say N = 5
for(int i = 0; i < N; i++) {
doSomething(i);
}
}
Does loop unrolling works differently in Scala? Will the JIT compiler treat the following code snippets the same way?
// Java
int N = getCount();
for(int i = 0; i < N; i++) {
doSomething(i);
}
// Scala
val N = getCount();
var i = 0
while(i < N) {
doSomething(i);
i+=1
}
The JIT compiler works on the Java bytecode so the unroll behaviour is independent of the original language and will depend on the particular JVM/compiler that is being used.
I don't believe that the Scala compiler implements its own loop unrolling. It is quite rare to use this kind of counting loop in Scala so it is probably not worth optimising it.

Java For-Loop - Termination Expression speed

In my java program I have a for-loop looking roughly like this:
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
for (int i = 0; i < myList.size(); i++) {
doWhatsoever();
}
Since the size of the list isn't changing, I tried to accelerate the loop by replacing the termination expression of the loop with a variable.
My idea was: Since the size of an ArrayList can possibly change while iterating it, the termination expression has to be executed each loop cycle. If I know (but the JVM doesn't), that its size will stay constant, the usage of a variable might speed things up.
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
int myListSize = myList.size();
for (int i = 0; i < myListSize; i++) {
doWhatsoever();
}
However, this solution is slower, way slower; also making myListSize final doesn't change anything to that! I mean I could understand, if the speed didn't change at all; because maybe JVM just found out, that the size doesn't change and optimized the code. But why is it slower?
However, I rewrote the program; now the size of the list changes with each cycle: if i%2==0, I remove the last element of the list, else I add one element to the end of the list. So now the myList.size() operation has to be called within each iteration, I guessed.
I don't know if that's actually correct, but still the myList.size() termination expression is faster than using just a variable that remains constant all the time as termination expression...
Any ideas why?
Edit (I'm new here, I hope this is the way, how to do it)
My whole test program looks like this:
ArrayList<Integer> myList = new ArrayList<Integer>();
for (int i = 0; i < 1000000; i++)
{
myList.add(i);
}
final long myListSize = myList.size();
long sum = 0;
long timeStarted = System.nanoTime();
for (int i = 0; i < 500; i++)
{
for (int j = 0; j < myList.size(); j++)
{
sum += j;
if (j%2==0)
{
myList.add(999999);
}
else
{
myList.remove(999999);
}
}
}
long timeNeeded = (System.nanoTime() - timeStarted)/1000000;
System.out.println(timeNeeded);
System.out.println(sum);
Performance of the posted code (average of 10 executions):
4102ms for myList.size()
4230ms for myListSize
Without the if-then-else statements (so with constant myList size)
172ms for myList.size()
329ms for myListSize
So the speed different of both versions is still there. In the version with the if-then-else parts the percentaged differences are of course smaller because a lot of the time is invested for the add and remove operations of the list.
The problem is with this line:
final long myListSize = myList.size();
Change this to an int and lo and behold, running times will be identical. Why? Because comparing an int to a long for every iteration requires a widening conversion of the int, and that takes time.
Note that the difference also largely (but probably not completely) disappears when the code is compiled and optimised, as can be seen from the following JMH benchmark results:
# JMH 1.11.2 (released 7 days ago)
# VM version: JDK 1.8.0_51, VM 25.51-b03
# VM options: <none>
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
...
# Run complete. Total time: 00:02:01
Benchmark Mode Cnt Score Error Units
MyBenchmark.testIntLocalVariable thrpt 20 81892.018 ± 734.621 ops/s
MyBenchmark.testLongLocalVariable thrpt 20 74180.774 ± 1289.338 ops/s
MyBenchmark.testMethodInvocation thrpt 20 82732.317 ± 749.430 ops/s
And here's the benchmark code for it:
public class MyBenchmark {
#State( Scope.Benchmark)
public static class Values {
private final ArrayList<Double> values;
public Values() {
this.values = new ArrayList<Double>(10000);
for (int i = 0; i < 10000; i++) {
this.values.add(Math.random());
}
}
}
#Benchmark
public double testMethodInvocation(Values v) {
double sum = 0;
for (int i = 0; i < v.values.size(); i++) {
sum += v.values.get(i);
}
return sum;
}
#Benchmark
public double testIntLocalVariable(Values v) {
double sum = 0;
int max = v.values.size();
for (int i = 0; i < max; i++) {
sum += v.values.get(i);
}
return sum;
}
#Benchmark
public double testLongLocalVariable(Values v) {
double sum = 0;
long max = v.values.size();
for (int i = 0; i < max; i++) {
sum += v.values.get(i);
}
return sum;
}
}
P.s.:
My idea was: Since the size of an ArrayList can possibly change while
iterating it, the termination expression has to be executed each loop
cycle. If I know (but the JVM doesn't), that its size will stay
constant, the usage of a variable might speed things up.
Your assumption is wrong for two reasons: first of all, the VM can easily determine via escape analysis that the list stored in myList doesn't escape the method (so it's free to allocate it on the stack for example).
More importantly, even if the list was shared between multiple threads, and therefore could potentially be modified from the outside while we run our loop, in the absence of any synchronization it is perfectly valid for the thread running our loop to pretend those changes haven't happened at all.
As always, things are not always what they seem...
First things first, ArrayList.size() doesn't get recomputed on every invocation, only when the proper mutator is invoked. So calling it frequently is quite cheap.
Which of these loops is the fastest?
// array1 and array2 are the same size.
int sum;
for (int i = 0; i < array1.length; i++) {
sum += array1[i];
}
for (int i = 0; i < array2.length; i++) {
sum += array2[i];
}
or
int sum;
for (int i = 0; i < array1.length; i++) {
sum += array1[i];
sum += array2[i];
}
Instinctively, you would say that the second loop is the fastest since it doesn't iterate twice. However, some optimizations actually cause the first loop to be the fastest depending, for instance, on memory walking strides that cause a lot of memory cache misses.
Side-note: this compiler optimization technique is called loop
jamming.
This loop:
int sum;
for (int i = 0; i < 1000000; i++) {
sum += list.get(i);
}
is not the same as:
// Assume that list.size() == 1000000
int sum;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
In the first case, the compile absolutely knows that it must iterate a million times and puts the constant in the Constant Pool, so certain optimizations can take place.
A closer equivalent would be:
int sum;
final int listSize = list.size();
for (int i = 0; i < listSize; i++) {
sum += list.get(i);
}
but only after the JVM has figured out what the value of listSize is. The final keyword gives the compiler/run-time certain guarantees that can be exploited. If the loop runs long enough, JIT-compiling will kick in, making execution faster.
Because this sparked interest in me I decided to do a quick test:
public class fortest {
public static void main(String[] args) {
long mean = 0;
for (int cnt = 0; cnt < 100000; cnt++) {
if (mean > 0)
mean /= 2;
ArrayList<String> myList = new ArrayList<String>();
putThingsInList(myList);
long start = System.nanoTime();
int myListSize = myList.size();
for (int i = 0; i < myListSize; i++) doWhatsoever(i, myList);
long end = System.nanoTime();
mean += end - start;
}
System.out.println("Mean exec: " + mean/2);
}
private static void doWhatsoever(int i, ArrayList<String> myList) {
if (i % 2 == 0)
myList.set(i, "0");
}
private static void putThingsInList(ArrayList<String> myList) {
for (int i = 0; i < 1000; i++) myList.add(String.valueOf(i));
}
}
I do not see the kind of behavior you are seeing.
2500ns mean execution time over 100000 iterations with myList.size()
1800ns mean execution time over 100000 iterations with myListSize
I therefore suspect that it's your code that is executed by the functions that is at fault. In the above example you can sometimes see faster execution if you only fill the ArrayList once, because doWhatsoever() will only do something on the first loop. I suspect the rest is being optimized away and significantly drops execution time therefore. You might have a similar case, but without seeing your code it might be close to impossible to figure that one out.
There is another way to speed up the code using for each loop
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
for (MyObject ob: myList) {
doWhatsoever();
}
But I agree with #showp1984 that some other part is slowing the code.

Going back to the first index after reaching the last one in an array

After my array in the for loop reaches the last index, I get an exception saying that the index is out of bounds. What I wanted is for it to go back to the first index until z is equal to ctr. How can I do that?
My code:
char res;
int ctr = 10
char[] flames = {'F','L','A','M','E','S'};
for(int z = 0; z < ctr-1; z++){
res = (flames[z]);
jLabel1.setText(String.valueOf(res));
}
You need to use an index that is limited to the size of the array. More precisely, and esoterically speaking, you need to map the for-loop iterations {0..9} to the valid indexes for the flame array {0..flames.length()-1}, which are the same, in this case, to {0..5}.
When the loop iterates from 0 to 5, the mapping is trivial. When the loop iterates a 6th time, then you need to map it back to array index 0, when it iterates to the 7th time, you map it to array index 1, and so on.
== Naïve Way ==
for(int z = 0, j = 0; z < ctr-1; z++, j++)
{
if ( j >= flames.length() )
{
j = 0; // reset back to the beginning
}
res = (flames[j]);
jLabel1.setText(String.valueOf(res));
}
== A More Appropriate Way ==
Then you can refine this by realizing flames.length() is an invariant, which you move out of a for-loop.
final int n = flames.length();
for(int z = 0, j = 0; z < ctr-1; z++, j++)
{
if ( j >= n )
{
j = 0; // reset back to the beginning
}
res = (flames[j]);
jLabel1.setText(String.valueOf(res));
}
== How To Do It ==
Now, if you are paying attention, you can see we are simply doing modular arithmetic on the index. So, if we use the modular (%) operator, we can simplify your code:
final int n = flames.length();
for(int z = 0; z < ctr-1; z++)
{
res = (flames[z % n]);
jLabel1.setText(String.valueOf(res));
}
When working with problems like this, think about function mappings, from a Domain (in this case, for loop iterations) to a Range (valid array indices).
More importantly, work it out on paper before you even begin to code. That will take you a long way towards solving these type of elemental problems.
While luis.espinal answer, performance-wise, is better I think you should also take a look into Iterator's as they will give you greater flexibility reading back-and-forth.
Meaning that you could just as easy write FLAMESFLAMES as FLAMESSEMALF, etc...
int ctr = 10;
List<Character> flames = Arrays.asList('F','L','A','M','E','S');
Iterator it = flames.iterator();
for(int z=0; z<ctr-1; z++) {
if(!it.hasNext()) // if you are at the end of the list reset iterator
it = flames.iterator();
System.out.println(it.next().toString()); // use the element
}
Out of curiosity doing this loop 1M times (avg result from 100 samples) takes:
using modulo: 51ms
using iterators: 95ms
using guava cycle iterators: 453ms
Edit:
Cycle iterators, as lbalazscs nicely put it, are even more elegant. They come at a price, and Guava implementation is 4 times slower. You could roll your own implementation, tough.
// guava example of cycle iterators
Iterator<Character> iterator = Iterators.cycle(flames);
for (int z = 0; z < ctr - 1; z++) {
res = iterator.next();
}
You should use % to force the index stay within flames.length so that they make valid index
int len = flames.length;
for(int z = 0; z < ctr-1; z++){
res = (flames[z % len]);
jLabel1.setText(String.valueOf(res));
}
You can try the following:-
char res;
int ctr = 10
char[] flames = {'F','L','A','M','E','S'};
int n = flames.length();
for(int z = 0; z < ctr-1; z++){
res = flames[z %n];
jLabel1.setText(String.valueOf(res));
}
Here is how I would do this:
String flames = "FLAMES";
int ctr = 10;
textLoop(flames.toCharArray(), jLabel1, ctr);
The textLoop method:
void textLoop(Iterable<Character> text, JLabel jLabel, int count){
int idx = 0;
while(true)
for(char ch: text){
jLabel.setText(String.valueOf(ch));
if(++idx < count) return;
}
}
EDIT: found a bug in the code (idx needed to be initialized outside the loop). It's fixed now. I've also refactored it into a seperate function.

Performance tips questions

public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
According to Android documentation, in above code, zero is slower. But I don't understand why ? well I haven't learn that much deep but as I know length is a field not method. So when loop retrieves its value, how its different from retrieving from local variable ? and array length is always fixed once initialized. What am I missing ?
Well I guess this is because at zero, he always needs to retrieve the information from mArray and in one, he has it accessible. This means, zero needs two "methods":
Access mArray
Access mArray.length
But one only needs one "methods":
Access len
In the first example, the JVM needs to first fetch the reference to the array and then access its length field.
In the second example, it only accesses one local variable.
On desktop JVMs this is generally optimised and the two methods are equivalent but it seems that Android's JVM does not do it... yet...
It is a matter of scope. Accessing an instance variable is slower than a method variable because it is not stored in the same memory places. (because method variables are likely to be accessed more often).
Same goes for len, but with an extra optimization. len cannot be changed from outside the method, and the compiler can see that it will never change. Therefore, its value is more predictable and the loop can be further optimized.
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
Here if you look at the for loop array length is calculated for every iteration, that degrades
the performance.
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
In this case the length is calculated before for loop and then used in the loop.

Efficient methods for Incrementing and Decrementing in the same Loop

Suppose some situations exist where you would like to increment and decrement values in the same for loop. In this set of situations, there are some cases where you can "cheat" this by taking advantage of the nature of the situation -- for example, reversing a string.
Because of the nature of building strings, we don't really have to manipulate the iterate or add an additional counter:
public static void stringReversal(){
String str = "Banana";
String forwardStr = new String();
String backwardStr = new String();
for(int i = str.length()-1; i >= 0; i--){
forwardStr = str.charAt(i)+forwardStr;
backwardStr = backwardStr+str.charAt(i);
}
System.out.println("Forward String: "+forwardStr);
System.out.println("Backward String: "+backwardStr);
}
However, suppose a different case exists where we just want to print a decremented value, from the initial value to 0, and an incremented value, from 0 to the initial value.
public static void incrementAndDecrement(){
int counter = 0;
for(int i = 10; i >= 0; i--){
System.out.println(i);
System.out.println(counter);
counter++;
}
}
This works well enough, but having to create a second counter to increment seems messy. Are there any mathematical tricks or tricks involving the for loop that could be used that would make counter redundant?
Well it looks like you just want:
for(int i = 10; i >= 0; i--){
System.out.println(i);
System.out.println(10 - i);
}
Is that the case? Personally I'd normally write this as an increasing loop, as I find it easier to think about that:
for (int i = 0; i <= 10; i++) {
System.out.println(10 - i);
System.out.println(i);
}
Note that your string example is really inefficient, by the way - far more so than introducing an extra variable. Given that you know the lengths involved to start with, you can just start with two char[] of the right size, and populate the right index each time. Then create a string from each afterwards. Again, I'd do this with an increasing loop:
char[] forwardChars = new char[str.length()];
char[] reverseChars = new char[str.length()];
for (int i = 0; i < str.length(); i++) {
forwardChars[i] = str.charAt(i);
reverseChars[reverseChars.length - i - 1] = str.charAt(i);
}
String forwardString = new String(forwardChars);
String reverseString = new String(reverseChars);
(Of course forwardString will just be equal to str in this case anyway...)
You can have multiple variables and incrementers in a for loop.
for(int i = 10, j = 0; i >= 0; i--, j++) {
System.out.println(i);
System.out.println(j);
}

Categories