Warum ist die removeRange () -Methode von Java's AbstractList geschützt?

98

Hat jemand eine Idee, warum die removeRange-Methode in AbstractList (und auch in ArrayList ) ist protected? Es sieht nach einer ziemlich gut definierten und nützlichen Operation aus, aber um sie zu verwenden, müssen wir die List-Implementierung in Unterklassen unterteilen.

Gibt es versteckte Gründe? Scheint mir ziemlich unerklärlich.

Joonas Pulakka
quelle

Antworten:

163

Ja, da Sie auf diese Weise keinen Bereich aus externem Code entfernen. Tun Sie stattdessen Folgendes:

list.subList(start, end).clear();

Dies ruft tatsächlich removeRangehinter die Kulissen.


Das OP fragt, warum removeRangenicht Teil der Listöffentlichen API ist. Der Grund ist in Punkt 40 von Effective Java 2nd ed beschrieben, und ich zitiere ihn hier:

Es gibt drei Techniken zum Verkürzen zu langer Parameterlisten. Eine besteht darin, die Methode in mehrere Methoden aufzuteilen, für die jeweils nur eine Teilmenge der Parameter erforderlich ist. Wenn dies unachtsam gemacht wird, kann dies zu zu vielen Methoden führen, aber es kann auch dazu beitragen , die Anzahl der Methoden zu verringern , indem die Orthogonalität erhöht wird. Betrachten Sie zum Beispiel die java.util.ListSchnittstelle. Es werden keine Methoden zum Auffinden des ersten oder letzten Index eines Elements in einer Unterliste bereitgestellt, für die beide drei Parameter erforderlich wären. Stattdessen wird die subListMethode bereitgestellt , die zwei Parameter verwendet und eine Ansicht einer Unterliste zurückgibt. Diese Methode kann mit den Methoden indexOfoder kombiniert lastIndexOfwerden, von denen jede einen einzelnen Parameter hat, um die gewünschte Funktionalität zu erhalten. Darüber hinaus ist diesubListDie Methode kann mit jeder Methode kombiniert werden, die mit einer ListInstanz arbeitet, um beliebige Berechnungen für Unterlisten durchzuführen. Die resultierende API hat ein sehr hohes Leistungsgewicht.

Man kann argumentieren, dass removeRangees nicht so viele Parameter gibt und daher wahrscheinlich kein Kandidat für diese Behandlung ist, aber da es eine Möglichkeit gibt, removeRangeüber das aufzurufen subList, gibt es keinen Grund, die ListSchnittstelle mit einer redundanten Methode zu überladen .


In der AbstractList.removeRangeDokumentation heißt es:

Diese Methode wird von der clearOperation in dieser Liste und ihren Unterlisten aufgerufen. Das Überschreiben dieser Methode, um die Interna der Listenimplementierung zu nutzen, kann die Leistung des Vorgangs für diese Liste und ihre Unterlisten erheblich verbessern clear.

Siehe auch OpenJDKs Implementierung von AbstractList.clearund SubList.removeRange.

Chris Jester-Young
quelle
9
Ok, das kann so gemacht werden, aber warum ? Scheint unangenehm. Einzelne Elemente können direkt aus der Liste entfernt werden. Warum dann nicht mehrere Elemente?
Joonas Pulakka
1
@Joonas: Punkt 40 von Effective Java, 2. Ausgabe, beschreibt die Gründe dafür. Ich werde den entsprechenden Abschnitt einfügen, falls Sie das Buch nicht haben.
Chris Jester-Young
21
+1 (Frage beantwortet). Nur weil eine Begründung gegeben ist, heißt das nicht, dass sie sinnvoll ist. Das Verkürzen von Parameterlisten behindert die Fähigkeit von Entwicklern, die in einer API verfügbaren Vorgänge zu verstehen, was direkt dem Grund entgegenwirkt, warum die Listen überhaupt gekürzt wurden.
Sam Harwell
3
So typisch für Java. Machen wir es am kompliziertesten und am wenigsten effektiv.
Tomáš Zato - Wiedereinsetzung Monica
2
Haben Sie als Randnotiz bemerkt, dass removeRangeAnrufe arraycopyunnötig sind, wenn die ArrayListVersion in einem Bereich verwendet wird, der bis zum Ende der Liste reicht? hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e2117e30fb39/src/share/… das numMovedist 0, sodass der gesamte Arraycopy-Code in einem einzigen if(wie in remove) ausgeführt werden könnte; Der Unterschied besteht darin, dass a) Arraycopy ein nativer Aufruf ist, der einen Overhead verursacht. b) Arraycopy überprüft die Parameter immer auf Richtigkeit. stackoverflow.com/questions/12594046/…