Différence entre Collection et Collections en Java

Deux noms très similaires et une source de confusion classique : java.util.Collection et java.util.Collections. Le premier est une interface, le second une classe utilitaire. Les deux sont au cœur du Java Collections Framework mais remplissent des rôles opposés.

Collection — l'interface racine

Collection<E> est l'interface dont héritent toutes les structures de données : List, Set, Queue. Elle définit les opérations de base applicables à tout groupe d'éléments.

public interface Collection<E> extends Iterable<E> {
    boolean add(E e);
    boolean remove(Object o);
    int size();
    boolean contains(Object o);
    boolean isEmpty();
    void clear();
    Iterator<E> iterator();
    // ...
}

On l'utilise comme type générique quand on accepte n'importe quelle collection :

public static <T> int taille(Collection<T> c) {
    return c.size();
}

// Accepte List, Set, Queue — ou toute autre implémentation
taille(new ArrayList<>());
taille(new HashSet<>());

Collections — la boîte à outils

Collections (avec un s) est une classe finale remplie de méthodes statiques qui opèrent sur des Collection existantes : tri, recherche, inversion, vues immuables, synchronisation.

public final class Collections {
    public static <T> void sort(List<T> list);
    public static <T> List<T> unmodifiableList(List<? extends T> list);
    public static <T> List<T> synchronizedList(List<T> list);
    public static <T> void reverse(List<?> list);
    public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key);
    // ...
}

Exemples d'usage de Collections

Trier une liste

List<Integer> nombres = new ArrayList<>(List.of(3, 1, 4, 1, 5, 9, 2, 6));
Collections.sort(nombres);
// [1, 1, 2, 3, 4, 5, 6, 9]

Inverser

Collections.reverse(nombres);
// [9, 6, 5, 4, 3, 2, 1, 1]

Min, max

int min = Collections.min(nombres); // 1
int max = Collections.max(nombres); // 9

Liste non modifiable

List<String> originale = new ArrayList<>(List.of("a", "b", "c"));
List<String> readOnly = Collections.unmodifiableList(originale);
readOnly.add("d"); // ❌ UnsupportedOperationException

Liste synchronisée

List<String> safe = Collections.synchronizedList(new ArrayList<>());
// Toutes les méthodes sont thread-safe individuellement

Collections vides / singleton

List<String> vide = Collections.emptyList();
List<String> un = Collections.singletonList("seul");
Set<Integer> unSet = Collections.singleton(42);

Recherche dichotomique

List<Integer> trie = List.of(1, 3, 5, 7, 9);
int index = Collections.binarySearch(trie, 5); // 2

Tableau récapitulatif

CollectionCollections
NatureInterfaceClasse finale
RôleDécrire ce qu'est une collectionFournir des outils pour les collections
Utilisation typiqueType de paramètre ou de retourMéthodes statiques
Instanciable ?Non (via ArrayList, etc.)Non (constructeur privé)
ExempleCollection<String> c = ...;Collections.sort(list);

L'évolution moderne

Depuis Java 8, les fonctions les plus utiles de Collections ont des équivalents directement sur les interfaces :

  • Collections.sort(list)list.sort(null)
  • Collections.reverse(list) → pas d'équivalent direct, mais list.reversed() depuis Java 21
  • Collections.unmodifiableList(list)List.copyOf(list) (Java 10+)
  • Collections.emptyList()List.of() (Java 9+)

Dans du code Java moderne, vous utiliserez Collections principalement pour les vues synchronisées et quelques cas particuliers.

Pièges fréquents

  • Collections.sort() modifie la liste sur place — elle doit donc être modifiable. List.of(...) est immuable et lève UnsupportedOperationException.
  • Collections.synchronizedList ne synchronise pas l'itération — enveloppez le for dans un synchronized(list) { ... }.
  • Collections.unmodifiableList est une vue : modifier la liste d'origine affecte la vue. List.copyOf fait une copie profonde de la référence.

En bref : Collection = la donnée, Collections = les outils. La différence d'un s change totalement le rôle.