Я задавался вопросом, size()
метод, что можно обратиться к существующему ArrayList<T>
кэшируемый? Или действительно ли это предпочтительно в производительности критический код, который я просто храню size()
в локальном интервале?
Я ожидал бы, что это действительно кэшируется, когда Вы не добавляете/удаляете объекты между вызовами к size()
.
Я прав?
обновление
Я не говорю о встраивании или таких вещах. Я просто хочу знать если метод size()
самостоятельно кэширует значение внутренне, или что оно динамично вычисляет каждый раз при вызове.
Я бы не сказал, что это "кэшируется" как таковое - но это просто хранится в поле, так что это достаточно быстро для частого вызова.
Реализация size()
в Sun JDK выглядит так:
public int size() {
return size;
}
Очевидной реализацией ArrayList было бы внутреннее сохранение размера в поле. Я был бы очень удивлен, если бы его когда-нибудь нужно было вычислить, даже после изменения размера.
Почему это должно быть так? ArrayList реализует интерфейс List, который поддерживается массивом, в конце концов.
Я бы предположил, что у него просто есть член size
, который увеличивается при вставке и уменьшается при удалении, а затем он просто возвращает его.
Хотя я не смотрел больше, чем API-документы.
Если кэширование результата метода size ()
заметно повысит производительность (что это иногда случается - я регулярно вижу ArrayList.size ()
как лучший скомпилированный метод в моем выводе -Xprof
), а затем рассматриваю возможность преобразования всего списка в массив для еще большего ускорения.
Вот один прием, который может сработать, если вы регулярно просматриваете список, но редко его обновляете:
class FooProcessor {
private Foo[] fooArray = null;
private List<Foo> fooList = new ArrayList<Foo>();
public void addFoo(Foo foo) {
fooList.add(foo);
fooArray = null;
}
public void processAllFoos() {
Foo[] foos = getFooArray();
for (int i = 0; i < foos.length; ++ i) {
process(foos[i]);
}
}
private void getFooArray() {
if (fooArray == null) {
Foo[] tmpArray = new Foo[fooList.size()];
fooArray = fooList.toArray(tmpArray);
}
return fooArray;
}
}
Да.
Быстрый взгляд на исходный текст Java подскажет вам ответ.
Это реализация в OpenJDK версии:
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
}
Так что это настолько хорошо, насколько может быть хорош вызов метода. Маловероятно, что HotSpot кэширует значение, возвращаемое этим методом, так что если вы действительно ТАК обеспокоены, вы можете кэшировать его самостоятельно. Если только профилирование не показало, что это узкое место (что маловероятно), вам следует беспокоиться о читабельности, а не о том, кэшируется или нет простой вызов метода, возвращающий значение поля.
Я не знаю ответа наверняка, но мое предположение: нет. У компилятора Java нет никакого способа, кроме специальной оболочки ArrayList, узнать, что вызываемые вами функции не будут мутирующими и что в результате вызов size() должен вернуть одно и то же значение. Поэтому я считаю маловероятным, что компилятор Java будет учитывать повторные вызовы size() и хранить их во временном значении. Если вам нужен такой уровень оптимизации, тогда вы должны сами хранить значение в локальной переменной. В противном случае, да, вы будете платить за накладные расходы на вызов функции, связанные с вызовом метода size(). Заметьте, однако, что метод size() является O(1) для ArrayList (хотя накладные расходы на вызов функции довольно велики). Лично я бы исключил все вызовы size() из циклов и вручную сохранял бы их в локале там, где это необходимо.
Редактировать
Хотя такая оптимизация не может быть выполнена компилятором Java, было верно подмечено, что JIT может инлайнить реализацию ArrayList.size() так, что это будет стоить столько же, сколько обращение к полю, без дополнительных накладных расходов на вызов метода, так что в действительности расходы пренебрежимо малы, хотя вы все равно можете немного сэкономить, сохраняя вручную во временной памяти (что потенциально может исключить поиск в памяти и вместо этого обслуживать переменную из регистра процессора).