For each loop :: 116 ms
Using collection.size() :: 36 ms
Using [int size = list.size(); int j = 0; j < size ; j++] :: 4 ms
Using [int j = list.size(); j > size ; j--] :: 1 ms
Reason for difference in performance
Type 1 is costliest one and simple reasoning is the use of iterator internally created in for each loop. Creating an iterator and calling iterator.get() adds up to most of cost which is not involved in direct access in other three types.
Type 2 uses size() method call every time and thus on runtime it brings a little overhead. Though JVM optimizes this code as inline call and other optimizations also and size method is simply a getter for size attribute of instance of list. Even though it brings a few more statements to execute at machine level code and which makes the difference.
Type 3 and 4 have a very little difference and should be considered as same, they both fetch the size of collection initially. And then uses this size value in loop for checking the condition.