Java: Über Arrays in Schnittstellen

von Hubert Schmid vom 2014-04-13

In dem Artikel 3 Good Reasons to Avoid Arrays in Java Interfaces beschreibt Ralf Sternberg, warum man Arrays als Parameter- und Rückgabetypen bei Interface-Methoden vermeiden sollte. Damit trifft er eine wertvolle Aussage zum Schnittstellenentwurf. Nur leider ist seine Argumentation dabei nicht hilfreich. Denn am Ende des Artikels bleibt vor allem hängen, Arrays wäre langsamer als ArrayLists. Ein Kommentar zu den Aussagen des Artikels.

Sind ArrayLists schneller als Arrays?

Zunächst sollte man bedenken, dass die Klasse ArrayList intern – wie der Name bereits andeutet – ein Array verwendet. Umso überraschender ist es, dass ArrayList trotzdem schneller sein soll. Doch tatsächlich gibt es einen Fall, den der Autor herausgegriffen hat: Eine ArrayList mit Typparameter T verwendet intern ein Feld vom Typ Object[] – und nicht vom Typ T[]. Letzteres wäre in Java auch nicht einfach zu realisieren. Und genau hieraus ergibt sich ein Unterschied in der Laufzeit zwischen den folgenden beiden Anweisungen:

In der ersten Anweisung wird unabhängig vom Typ T ein Feld vom Typ Object[] in ein anderes Feld des selben Typs kopiert. Die zweite Anweisung kopiert dagegen das Object[] in ein Feld vom Typ T[]. Dabei muss für jede einzelne, kopierte Referenz überprüft werden, ob der dynamische Typ zu T kompatibel ist.

Selbstverständlich verursacht das einen Overhead. Das ist der gleiche Overhead, der umgekehrt beim Lesen eines Elements auftritt. So gibt es auch einen Laufzeitunterschied bei den folgenden beiden Anweisungen, nur dass dieses Mal das Array die Nase vorne hat.

Daher finde ich so generelle Aussagen zur Performance fragwürdig, und zweifle an der Existenz einer realen Applikation, bei der obiger Performance-Vorteil der ArrayList einen wirtschaftlich relevanten Unterschied macht. Unabhängig davon halte ich es für ein zweifelhaftes Kriterium guten Schnittstellenentwurfs.

Sind ArrayLists Objekt-orientierter als Arrays?

Welcher der beiden Typen Objekt-orientierter ist, hängt davon ab, was man unter Objekt-Orientierung versteht. Dazu gibt es natürlich unterschiedliche Ansichten. Doch unabhängig davon sind aus meiner Sicht weder Arrays noch ArrayLists gute Beispiele für Objekt-Orientierung. Denn beide Typen definieren sich in erster Linie über ihren Inhalt anstatt ihr Verhalten, und in beiden Fällen sind die mit den Instanzen verbundenen Identitäten nicht hilfreich.

Unabhängig davon: Ist es für den Schnittstellenentwurf überhaupt relevant, wie Objekt-orientiert Parameter- oder Rückgabetypen sind? Sollte man in Schnittstellen etwa Integer gegenüber dem primitiven Typ int bevorzugen? Wohl kaum. Wichtig ist, sich in Schnitstellen an der Anforderungen des Aufrufers zu orientieren, und wenn für den Aufrufer Arrays hilfreicher sind, dann nützt es eben nichts, wenn man stattdessen eine ArrayList zurückgibt.

Sind ArrayLists Typ-sicherer als Arrays?

Was ist der Unterschied der folgenden beiden Anweisungen, wobei die Variable list vom statischen Typ ArrayList<CharSequence> und die Variable array vom statischen Typ CharSequence[] ist?

Bei der zweiten Anweisung muss im Gegensatz zur ersten Anweisung zur Laufzeit überprüft werden, ob der dynamische Typ von array tatsächlich zu String kompatibel ist. Falls der Typ inkompatibel ist – beispielsweise weil es sich um ein StringBuilder[] handelt – wirft die Zuweisung eine ArrayStoreException.

Und was ist der Unterschied zwischen den folgenden beiden Anweisungen?

Bei der ersten Anweisung muss im Gegensatz zur zweiten Anweisung zur Laufzeit überprüft werden, ob der dynamische Typ des zurückgegebenen Elements tatsächlich zu CharSequence kompatibel ist. Falls der dynamische Typ nicht kompatibel ist, wird bei der Zuweisung eine ClassCastException geworfen.

Was heißt das nun? Unabhängig davon was man unter Typ-Sicherheit versteht, und inwiefern man dabei zwischen statischer und dynamischer Typ-Prüfung unterscheidet, haben ArrayLists und Arrays in dieser Hinsicht praktisch die gleichen Eigenschaften. Für die Vermeidung von Arrays in Schnittstellen kann Typ-Sicherheit also kein Argument sein.

Trotzdem: Ungeachtet der fragwürdigen Argumentation des genannten Artikels ist an der eigentlich Aussage natürlich etwas Wahres dran: Arrays als Parameter- oder Rückgabetypen bei Schnittstellen-Methoden können ein Problem darstellen. Beispielsweise könnten sie das Kapselungsprinzip verletzen – wohlgemerkt des Objekts, das die Schnittstelle realisiert, und nicht des Objekts, das an der Schnittstelle übertragen wird.