Этот ответ с точки зрения C #, но я думаю, что то же самое относится и к Java.
В C # идиома
for (int i = 0; i < a.length; i++) { ...}
распознается как итерация по массиву, поэтому проверка границ избегается при доступе к массиву в цикле, а не при каждом доступе к массиву.
Это может быть или не быть распознано с помощью кода, такого как:
for (int i = 0, n = a.length; i < n; i++) { ...}
или
n = a.length;
for (int i = 0; i < n; i++) { ...}
Какую часть этой оптимизации выполняет компилятор по сравнению с JITter, я не знаю, и, в частности, если бы она выполнялась JITter, я ожидал бы, что все 3 сгенерируют один и тот же собственный код.
Однако, первая форма также, возможно, более читабельна для людей, поэтому я бы сказал, что согласен с этим.