Dlaczego metoda removeRange () Java's AbstractList jest chroniona?

98

Czy ktoś ma jakiś pomysł, dlaczego metoda removeRange w AbstractList (a także w ArrayList ) jest protected? Wygląda na całkiem dobrze zdefiniowaną i użyteczną operację, ale aby z niej skorzystać, jesteśmy zmuszeni do podklasy implementacji List.

Czy jest jakieś ukryte uzasadnienie? Wydaje mi się to zupełnie niewytłumaczalne.

Joonas Pulakka
źródło

Odpowiedzi:

163

Tak, ponieważ nie w ten sposób można usunąć zakres z zewnętrznego kodu. Zamiast tego zrób to:

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

To faktycznie wywołuje removeRangeza kulisami.


OP pyta, dlaczego removeRangenie jest częścią Listpublicznego API. Powód jest opisany w pozycji 40 Effective Java 2nd ed i cytuję go tutaj:

Istnieją trzy techniki skracania zbyt długich list parametrów. Jednym z nich jest rozbicie metody na wiele metod, z których każda wymaga tylko podzbioru parametrów. Jeśli zostanie to zrobione niedbale, może to prowadzić do zbyt wielu metod, ale może również pomóc zmniejszyć liczbę metod poprzez zwiększenie ortogonalności. Weźmy na przykład pod uwagę java.util.Listinterfejs. Nie zapewnia metod wyszukiwania pierwszego lub ostatniego indeksu elementu na liście podrzędnej, które wymagałyby trzech parametrów. Zamiast tego udostępnia subListmetodę, która przyjmuje dwa parametry i zwraca widok podlisty. Tę metodę można łączyć z metodami indexOflub lastIndexOf, z których każda ma jeden parametr, aby uzyskać żądaną funkcjonalność. PonadtosubListmetodę można łączyć z dowolną metodą działającą na Listinstancji w celu wykonywania dowolnych obliczeń na podlistach. Powstały API ma bardzo wysoki stosunek mocy do masy.

Można argumentować, że removeRangenie ma tak wielu parametrów i dlatego prawdopodobnie nie jest kandydatem do tego zabiegu, ale biorąc pod uwagę, że istnieje sposób wywołania removeRangeprzez subList, nie ma powodu, aby zaśmiecać Listinterfejs metodą nadmiarową.


AbstractList.removeRange dokumentacja mówi:

Ta metoda jest wywoływana przez clearoperację na tej liście i jej listach podrzędnych. Zastępowanie tej metody w celu wykorzystania elementów wewnętrznych implementacji listy może znacznie poprawić wydajność clearoperacji na tej liście i jej listach podrzędnych.

Zobacz także implementację AbstractList.cleari SubList.removeRange.

Chris Jester-Young
źródło
9
Ok, można to zrobić w ten sposób, ale dlaczego ? Wydaje się niezręczne. Pojedyncze elementy można usuwać bezpośrednio z listy, dlaczego więc nie wiele elementów?
Joonas Pulakka,
1
@Joonas: Pozycja 40 Efektywnej Java, wydanie drugie opisuje uzasadnienie tego. Wkleję w odpowiedniej sekcji, jeśli nie masz książki.
Chris Jester-Young
21
+1 (odpowiedź na pytanie). Jednak to, że podano uzasadnienie, nie oznacza, że ​​ma to sens. Proces skracania list parametrów utrudnia programistom zrozumienie operacji dostępnych w API, co działa bezpośrednio przeciwko powodowi, dla którego listy zostały skracane w pierwszej kolejności.
Sam Harwell,
3
Tak typowe dla Java. Zróbmy to najbardziej skomplikowane i najmniej efektywne.
Tomáš Zato - Przywróć Monikę
2
na marginesie, czy zauważyłeś, że removeRangewywołuje arraycopyniepotrzebne, gdy ArrayListwersja jest używana w zakresie obejmującym do samego końca listy? hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e2117e30fb39/src/share/ ... to numMovedjest 0, więc cały kod arraycopy można umieścić w jednym if(tak jak to zrobiono remove); różnica polega na tym, że a) arraycopy to wywołanie natywne, powodujące narzut, b) arraycopy zawsze sprawdza parametry pod kątem poprawności stackoverflow.com/questions/12594046/ ...