One scenario I can think of where a NullPointerException will be thrown in the second case is when addCard or dealCard somehow changes what players refer to (presumably neither modifies the content of players, because that would cause a ConcurrentModificationException in the first snippet).
Here's an example (please run this on your own if you have any doubts):
import java.util.*;
public class ForEachVS {
static List<Integer> players;
static void process(int i) {
System.out.println(i);
players = null;
}
public static void main(String args[]) {
players = Arrays.asList(1,2,3);
for (int p : players) {
process(p);
} // this processes 1,2,3
players = Arrays.asList(1,2,3);
for (int i = 0; i < players.size(); i++) {
process(players.get(i));
} // this processes 1, then throws NullPointerException
}
}
So as you can see, the two constructs are actually NOT exactly equivalent. The essence of the above snippet is concisely presented here:
int[] arr;
arr = new int[5];
for (int x : arr) {
arr = null;
}
arr = new int[5];
for (int i = 0; i < arr.length; i++) {
arr = null;
}
You will find out that the first loop went fine, while the second loop throws NullPointerException. So while it's true most of the time, the two constructs are not exactly 100% equivalent.