1. Ce qui se passe : une exception est levée

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)

En effet, une boucle for-each utilise un itérateur et on sait que l'utilisation des méthodes next ou remove de l'itérateur provoquent la levée de cette exception si la collection a été modifiée directement sans passer par l'itérateur. Dans ce cas particulier, l'employé "John" est supprimé directement par "employes.remove(employe)" et donc l'exception est levée quand Bob, l'employé suivant est récupéré par l'itérateur avec sa méthode next.

2. L'exception a lieu quand on veut utiliser l'itérateur après une modification. Mais ici aucune exception n'est lancée. Pourquoi ?

Si on commente les lignes qui ajoutent Fred et Pierre, la liste contient Tom, John et Bob. Lorsque la liste est parcourue, John est enlevé de la liste. La suppression d'un élément d'un ArrayList décale les éléments dans le tableau utilisé par l'ArrayList. Bob se retrouve avec l'indice 1 et la taille de la liste est décrémentée. L'itérateur pense être arrivé au bout de la liste (il appelle la méthode hasNext qui ne lance pas l'exception ConcurrentModificationException ; seules les méthode next et remove la lance) et donc Bob ne sera pas examiné (pas d'appel de la méthode next de l'itérateur) et aucune exception ne sera levée car l'itérateur ne sera pas utilisé après la modification de la liste ! C'est pour cela que Bob apparait à la fin alors qu'il gagne plus de 10.000.

3. Pour enlever les employés de la liste il faut utiliser la méthode remove de l'itérateur et donc utiliser une boucle dans laquelle l'itérateur apparait (il est caché par la boucle for-each et on ne peut donc pas appeler sa méthode remove). On peut utiliser une boucle for ordinaire ou utiliser une boucle while.

Avec une boucle for ordinaire :

for(Iterator<Employe> it = employes.iterator(); it.hasNext(); ) {
  if (it.next().getSalaire() > 10_000) {
    it.remove();
  }
}

Avec une boucle while :

Iterator<Employe> it = employes.iterator();
while (it.hasNext()) {
  if (it.next().getSalaire() > 10_000) {
    it.remove();
} }

Si on travaillait avec une collection qui n'est pas une liste on n'aurait pas d'autre solution. Avec une liste on peut aussi utiliser une boucle for ordinaire mais sans passer par un itérateur. Cependant il faut encore faire attention à parcourir la liste en partant de la fin pour ne pas avoir à tenir compte du décalage lors d'une suppression. Le code :

for(int i = employes.size() - 1; i >= 0; i--) {
  Employe employe = employes.get(i);
  if (employe.getSalaire() > 10_000) {
    employes.remove(employe);
  }
}

Java 8 a introduit la méthode removeIf dans l'interface Collection. C'est la méthode la plus simple pour supprimer tous les éléments d'une liste qui vérifient un certain critère mais vous ne pourrez la comprendre qu'après avoir étudié les expressions lambda (dernière partie de ce cours) :

employes.removeIf(employe -> employe.getSalaire() > 10_000);
System.out.println(employes);