Вызов метода считывания многократно или вызов однажды и присвоение переменной?

скажите предполагают, что у меня есть класс как:

public class Age {

    private int age;

    public int getAge() {
       return this.age;
    }

}

В моем Основном классе я звоню getAge() метод много раз.

Таким образом, я хотел знать, это желательный, чтобы звонить так много раз или звонить однажды и присвоить его некоторой переменной и использованию та переменная.

Который является лучшим и почему?

13
задан Lavekush Agrawal 2 January 2018 в 05:37
поделиться

12 ответов

Не пытайтесь микрооптимизировать это, если вы не обнаружите, что это действительно узкое место при профилировании. Я бы использовал метод доступа getAge (), поскольку это, скорее всего, наиболее удобное и очевидное решение.

При этом оба подхода, вероятно, будут работать одинаково. Во время выполнения JIT, скорее всего, полностью оптимизирует вызов getAge (), поэтому в обоих случаях это будет единственный примитивный доступ.

7
ответ дан 1 December 2019 в 21:11
поделиться

Вероятно, это ситуация, когда вы оптимизируете, прежде чем знаете, что вам нужно. Это просто целое число, поэтому оно не занимает много памяти, если вы храните значение в нескольких местах. В то же время это очень простой вызов метода, выполнение которого не займет много времени. Напишите это так, как вы считаете, наиболее читаемым. Затем, когда у вас будет надежная версия кода, вы можете использовать инструмент профилирования, чтобы увидеть, есть ли заметная разница.

10
ответ дан 1 December 2019 в 21:11
поделиться

При многократном вызове метода getAge() возможен некоторый перерасход производительности, но я предлагаю вам рассмотреть Печальную трагедию театра микрооптимизации.

3
ответ дан 1 December 2019 в 21:11
поделиться

Это то, что вы, как автор API, должны указать вызывающей стороне.

В общем, если вы просто возвращаете свойство, вы можете пометить вызов как финальный (если вы не предлагаете фактический интерфейс). Это должно снизить стоимость вызовов, поскольку компилятор с большей вероятностью будет инлайнить функцию.

Если стоимость вычисления свойства дорогая (например, поиск строки), задокументируйте это в JAvaDocs для данного метода и укажите вызывающей стороне, что она может захотеть получить значение один раз и кэшировать его.

3
ответ дан 1 December 2019 в 21:11
поделиться

Не беспокойтесь. Совершенно не стоит делать такую ​​микрооптимизацию. Подождите, пока вы закончите свой код, тогда он будет работать слишком медленно, затем достаньте профилировщик и работайте над тем, что профилировщик сообщает вам, что является источником проблемы.

Преждевременная оптимизация - корень всех зол.

2
ответ дан 1 December 2019 в 21:11
поделиться

Сложная часть состоит в том, чтобы понять, что современные JVM выполняют агрессивную оптимизацию при компиляции байтового кода на основе знаний, доступных во время выполнения.

Если, например, данный метод не переопределен в подклассе, он может обрабатываться точно так же, как конечный метод, позволяя JVM встроить копию своего кода в вызывающий метод вместо явного вызова метода. . (Если условия меняются, эти классы просто считаются новыми и, следовательно, перекомпилируются позже на основе новых условий).

Это означает, что get / set для атрибутов bean-компонентов (где значения просто сохраняются и извлекаются, а не вычисляются) очень дешевы, и вы должны выполнять вызовы каждый раз и ожидать, что JVM обнаружит возможные оптимизации и применит их.

0
ответ дан 1 December 2019 в 21:11
поделиться

Думаю, вы не увидите разницы во время выполнения - при условии, что вы не создадите более одного класса Age.

0
ответ дан 1 December 2019 в 21:11
поделиться

Для такого простого случая я бы выбрал тот, который выглядит лучше всего с точки зрения кода.

Есть несколько случаев, когда рекомендуется вызвать один раз и прочитать сохраненное возвращаемое значение, например, в

for (int i = 0; i < list.size(); i++)
    doSomethingThatDoesNotAffectSizeOfList();

, поскольку у компилятора могут возникнуть проблемы с определением того, влияет ли тело цикла на размер списка. Правильно реализованный список всегда должен легко определять его размер, но в других примерах (или при работе с плохо реализованными коллекциями) это может быть хуже.

В общем, если метод требует больших вычислительных ресурсов, вы можете использовать мемоизацию , что в основном означает, что вы кэшируете уже вычисленные значения ввода / вывода.

Мемоизированная функция «запоминает» результаты, соответствующие некоторому набору определенных входных данных. Последующие вызовы с запомненными входными данными возвращают запомненный результат, а не пересчитывают его, тем самым устраняя первичную стоимость вызова с заданными параметрами из всех, кроме первого вызова функции с этими параметрами.

Этот метод вводит принцип «сохранить возвращаемое значение для эффективности» в сам метод, что упрощает обслуживание - бла-бла-бла ...

0
ответ дан 1 December 2019 в 21:11
поделиться

Я постараюсь сказать с помощью примеров кода то, что уже было сказано в другом ответе.

В случае, если вы представили вызов getAge() очень просто, а стоимость его вызова практически ничтожна. Не беспокойтесь об этом в этом случае.

Но если ваш getAge был чем-то причудливым, что делает много вычислений или получает доступ к ресурсам ввода-вывода,like:

public int getAge() {
   return slowService.calculateAgeByBirthDate(birthDate); // it takes 2 seconds to execute for every call
}

Тогда наверняка было бы неплохо кэшировать de result и использовать его. Потому что, если вы вызовете его 30 раз, ваш код займет 1 минуту.

1
ответ дан 1 December 2019 в 21:11
поделиться

Вы не увидите большого изменения в производительности, если только не будете выполнять много операций внутри метода getAge().

0
ответ дан 1 December 2019 в 21:11
поделиться

В зависимости от того, как устроено ваше приложение, эти два варианта могут дать разные результаты! Если экземпляр age, который вы используете, является общим и изменяемым, различные места в вашем приложении могут изменить его значение между вызовами getAge(). В этом случае вопрос о том, какой вариант лучше для вашего кода, является вопросом корректности, и решать вам. Как гласит старая пословица: "сначала сделай правильно, потом сделай быстро". И, как уже отмечали другие, в данном случае вам, вероятно, не нужно беспокоиться о части "сделать быстро".

Смежный пример - когда вы изменяете коллекцию во время итерации по ней. Чтобы не получить ConcurrentModificationException, нужно выполнять итерацию над снимком.

1
ответ дан 1 December 2019 в 21:11
поделиться

В этом случае я бы посоветовал не смотреть на производительность, а на удобство использования и повторное использование кода. Ваша текущая реализация - простейший из геттеров, возвращающий целое число.

Но что, если где-то в будущем вы сохраните дату рождения человека и захотите динамически генерировать возраст? Если вы просто вызываете свойство напрямую, вам придется реорганизовать код. Однако, изменив внутреннее устройство getAge (), вы можете поместить туда вычисление, и все готово.

Мне бы очень хотелось, чтобы в языках программирования был введен модификатор «суперсекретное» свойство / поле, который в основном гласит: «Вы можете получить доступ к этому свойству только через его средство доступа».

0
ответ дан 1 December 2019 в 21:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: