Геттеры вредны для производительности в Java? - PullRequest
0 голосов
/ 09 ноября 2011

Учитывая следующие два варианта кода, есть ли какое-либо преимущество в производительности (в очень крупном масштабе или в течение длительного периода времени) секунды по сравнению с первым?

Опция 1

private Map<Long, Animal> animals = ...;
public Map<Long, Animal> getAnimals() {
    return animals;
}

public void useAnimals() {
    for (int i=0; i < SOME_LARGE_NUMBER; i++) {
        Animal animal = getAnimals().get(id);
    }
    // Many many calls to getAnimals() are made...
}

Вариант 2 - нет получателя

private Map<Long, Animal> animals = ...;

public void useAnimals() {
    for (int i=0; i < SOME_NUMBER; i++) {
        Animal animal = animals.get(id);
    }
    // No method calls made
}

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

И, будет ли сохранение результата getAnimals() в качестве локального значения ...

  • , если SOME_NUMBER - это сотни или тысячи?
  • , если SOME_NUMBER только в порядке величины 10?

Примечание : я ранее сказал "инкапсуляция".Я изменил его на «getter», потому что цель на самом деле не в том, что поле нельзя изменить, а в том, что его нельзя переназначить.Инкапсуляция - это просто снятие ответственности за присваивание из подклассов.

Ответы [ 4 ]

7 голосов
/ 09 ноября 2011

Скорее всего, JVM встроит getAnimals() вызов в узком цикле, фактически возвращаясь к Опция 1 . Так что не беспокойтесь, это действительно микро (нано?) Оптимизация.

Другая вещь - это переход с поля доступа к локальной переменной. Это звучит хорошо, поскольку вместо обхода ссылки this каждый раз, когда у вас всегда есть ссылка в стеке (два обращения к памяти против одного). Однако я считаю (поправьте меня, если я ошибаюсь), поскольку animals является частным и не volatile снова, JVM выполнит эту оптимизацию для вас во время выполнения.

5 голосов
/ 09 ноября 2011

Второй фрагмент больше инкапсулирован, чем первый.Первый дает доступ к внутренней карте любому, в то время как второй хранит ее в классе.

Оба приведут к сопоставимой производительности.

РЕДАКТИРОВАТЬ: так как вы измените вопрос, яТакже изменит ответ.

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

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

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

3 голосов
/ 09 ноября 2011

Профилировали ли вы это, чтобы увидеть, имеет ли это значение, для современного JIT я бы предположил , что он был бы оптомен, особенно если бы animals был отмечен final, но ничто не мешает вам тестироватьэто сам.

В любом случае, я на 100% это НИКОГДА не будет вашей бутылочной горловиной в приложении.

0 голосов
/ 09 ноября 2011

Ну, я не думаю, что JVM встроит вызов функции.Так что, вероятно, это может повлиять на производительность.Лучше всего создать локальную переменную и присвоить ей животных поля класса.

...