Почему защищен метод removeRange () в абстрактном списке Java?

98

Кто-нибудь знает, почему метод removeRange в AbstractList (а также в ArrayList ) есть protected? Это выглядит как довольно хорошо определенная и полезная операция, но тем не менее, чтобы использовать ее, мы вынуждены создать подкласс реализации List.

Есть какое-то скрытое обоснование? Мне это кажется совершенно необъяснимым.

Йоонас Пулакка
источник

Ответы:

163

Да, потому что это не способ удаления диапазона из внешнего кода. Вместо этого сделайте следующее:

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

На самом деле это звонки removeRangeза кулисами.


OP спрашивает, почему removeRangeне является частью Listобщедоступного API. Причина описана в правиле 40 2-го издания Effective Java, и я цитирую его здесь:

Есть три метода сокращения слишком длинных списков параметров. Один из них - разбить метод на несколько методов, каждый из которых требует только подмножества параметров. Если сделать это неаккуратно, это может привести к слишком большому количеству методов, но это также может помочь уменьшить количество методов за счет увеличения ортогональности. Например, рассмотрим java.util.Listинтерфейс. Он не предоставляет методов для поиска первого или последнего индекса элемента в подсписке, оба из которых требуют трех параметров. Вместо этого он предоставляет subListметод, который принимает два параметра и возвращает представление подсписка. Этот метод можно комбинировать с методами indexOfили lastIndexOf, каждый из которых имеет единственный параметр, чтобы получить желаемую функциональность. Более того,subListМетод можно комбинировать с любым методом, который работает с Listэкземпляром, для выполнения произвольных вычислений над подсписками. Полученный API имеет очень высокое соотношение мощности к весу.

Можно утверждать, что у removeRangeнего не так много параметров и, следовательно, он, вероятно, не является кандидатом для этого лечения, но, учитывая, что есть способ вызвать removeRangeчерез subList, нет причин загромождать Listинтерфейс избыточным методом.


В AbstractList.removeRangeдокументации говорится:

Этот метод вызывается clearоперацией над этим списком и его подсписками. Переопределение этого метода для использования преимуществ внутренней реализации списка может существенно улучшить производительность clearоперации над этим списком и его подсписками.

Также см. Реализацию OpenJDK AbstractList.clearи SubList.removeRange.

Крис Джестер-Янг
источник
9
Хорошо, так можно, но почему ? Кажется неудобным. Отдельные элементы могут быть удалены из списка напрямую, почему тогда не несколько элементов?
Joonas Pulakka
1
@Joonas: Правило 40 Эффективной Java, 2-е изд. Описывает обоснование этого. Я вставлю соответствующий раздел, если у вас нет книги.
Крис Джестер-Янг,
21
+1 (ответ на вопрос). Однако то, что дано обоснование, не означает, что оно имеет смысл. Процесс сокращения списков параметров мешает разработчикам понимать операции, доступные в API, что напрямую работает против причины, по которой списки были сокращены в первую очередь.
Сэм Харвелл,
3
Так типично для java. Сделаем его максимально сложным и наименее эффективным.
Tomáš Zato - Reinstate Monica
2
в качестве примечания, заметили ли вы, что removeRangeвызовы arraycopyбез надобности, когда ArrayListверсия используется в диапазоне, охватывающем до самого конца списка? hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e2117e30fb39/src/share/… значение numMovedравно 0, поэтому весь код копирования массива можно было бы поместить в один if(как сделано в remove); разница в том, что a) копирование массива является собственным вызовом, вызывающим накладные расходы, б) копирование массива всегда проверяет параметры на правильность stackoverflow.com/questions/12594046/…