2

There are similar questions :

Advanced for loop does cache reference because it's using the same iterator instance : https://stackoverflow.com/a/29812538/4087512

Normal for loop does cache length : https://stackoverflow.com/a/1208331/4087512

But I'm trying to see if the reference is cached in a classic for-loop :

for(int i=0; i<someObject.getPrivateArray().length; i++){
    //do something where it's necessary to use i AND getPrivateArray()
}

as opposed to :

int j=0;
for(int var : someObject.getPrivateArray()){
    //do something with j & var
    j++;
}

From the question answered here : Is there a performance difference between a for loop and a for-each loop? these 2 would have the same performance on an array declared in a local scope, but will there be an overhead of fetching the array from a different object for the for-loop? It was answered above that the array is actually cached in the foreach loop.

Zee
  • 824
  • 11
  • 25
  • 2
    Compile, disassemble (`javap -c -p`), and check? – chrylis -cautiouslyoptimistic- Jul 18 '19 at 01:27
  • If you know that calling `someObject.getPrivateArray()` is costly, then why not store its value in a local variable and use that variable both in the loop declaration and body? – ernest_k Jul 18 '19 at 01:28
  • @ernest_k well, the answer to that will answer my question. if `for` doesn't cache it and requires me to declare a new local variable, then i wouldn't use `for` at all because `foreach` does that and only calls `someObject.getPrivateArray()` once – Zee Jul 18 '19 at 01:32
  • @chrylis it still remains a valid question whether i answer it myself or not :) – Zee Jul 18 '19 at 01:34

1 Answers1

3

No.

Java has no way of knowing that someObject.getPrivateArray() will return the same object at each call. Therefore, it must call the function at each and every iteration.

Eg)

Queue<int[]> queue = ...;

for(int i=0; i<queue.remove().length; i++) {
    // ...
}

This is exactly the same pattern of code; only the names have changed, yet it is pretty clear the return value of queue.remove() won’t be cached.


Update

@MattTimmermans points out in a comment that the JVM could possibly in-line the someObject.getPrivateArray() call, so that the JVM might be able to determine the same object is being returned each time, and optimize away the call. This would require:

  • someObject be final or effectively final
  • getPrivateArray() be final, so it can be inlined
  • getPrivateArray() must be side-effect free (or the side effects must be executed anyway)
  • the returned value must be final so that some other entity can’t modify it, guaranteeing the same value is returned

In this case, the JVM might optimize the call away and move the fetch out of the loop, so effectively caching the result. I wouldn’t rely on it, when caching the value yourself is easy to do.

AJNeufeld
  • 8,526
  • 1
  • 25
  • 44
  • 1
    No... but sometimes yes, if it can figure out how to inline the call to `getPrivateArray()` – Matt Timmermans Jul 18 '19 at 02:09
  • `someObject` would have to be an effectively final local, or a final global, so it can’t change. `getPrivateArray()` would need to be final, so it can be inlined, would need to not have any side effects, and return a final member so that it can’t be modified by another entity. If all those ducks are in a row, then yes, the JVM might optimize away the repeated calls and use a cached result. – AJNeufeld Jul 18 '19 at 02:54