JLS 14.14.1.2 states (Expression here being the middle bit of the for statement):
Next, a for iteration step is performed, as follows. If the Expression is present, it is evaluated.
That means it does it on each iteration step, there is no leeway there in the specification for optimisation.
You can see something similar with the following code:
class Test {
public static int getSeven () {
System.out.println ("called getSeven()");
return 7;
}
public static void main (String[] args){
for (int i = 1; i <= getSeven(); i++) {
System.out.println ("i = " + i);
}
}
}
When you run that, you get:
called getSeven()
i = 1
called getSeven()
i = 2
called getSeven()
i = 3
called getSeven()
i = 4
called getSeven()
i = 5
called getSeven()
i = 6
called getSeven()
i = 7
called getSeven()
showing that the function is called each time through the loop (including the exit condition).
That means your particular case won't call it once or three times, it will actually call it four times, with idx set respectively to 0, 1, 2 and the final check at 3.