SubList in Java – unbekannte Gefahren


Es ist nur ein View!

Die Methode subList des Interfaces List gibt im Allgemeinen keine Liste, sondern ein View auf die Originalliste zurück. Achtung: Das Verhalten kann je Implementierung variieiern.

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
List<Integer> subList = list.subList(1, 4);
// Ändert den zersten Eintrag der subList und damit den zweiten der Originalliste
subList.set(1, 99); 
// Die Ausgangsliste wurde geändert
LOG.info(list); // Ausgabe: [1, 99, 3, 4, 5]

ConcurrentModificationException bei Strukturänderungen

Folgendes hat in einem unserer Projekte zu Problemen geführt. Wenn Änderungen an der Struktur der Original-Liste vorgenommen werden z. B. durch

  • add(),
  • remove() oder
  • clear()

während eine subList existiert, wirft der Zugriff auf die subList eine ConcurrentModificationException.

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
List<Integer> subList = list.subList(1, 4);
// Strukturänderung an der Original-Liste
list.clear(); 
// ConcurrentModificationException beim Zugriff
subList.get(0); 

Änderungen der Sublist finden sich in der Ausgangsliste

Ein subList().clear() verändert die Ausgangsliste.

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
List<Integer> subList = list.subList(1, 4);

subList.clear(); // Entfernt Elemente 2, 3, 4 aus der Original-Liste
System.out.println(list); // Ausgabe: [1, 5]

Und nun?

Sublisten sollten immer an einen Konstrukktor übergeben und damit eine Kopie erzeugt werden.

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
// Neues Listenobjekt erzeugen, das unabhängig ist
List<Integer> subListCopy = new ArrayList<>(list.subList(1, 4));

Du hast Fragen oder Anmerkungen? Kontakt: arndt@schoenb.de