Насколько плохо объявлять массивы внутри цикла for в Java? - PullRequest
2 голосов
/ 02 сентября 2011

Я пришел из C-фона, поэтому я признаю, что все еще борюсь с отказом от управления памятью при написании на Java. Вот одна проблема, которая возникла несколько раз, и я хотел бы получить некоторые уточнения. Вот два способа написания одной и той же подпрограммы, единственное отличие заключается в объявлении double[] array:

Пример кода 1 :

double[] array;
for (int i=0; i<n; ++i) {
    array = calculateSomethingAndReturnAnArray(i);
    if (someFunctionOnArrays(array)) {
        // DO ONE THING
    } else {
        // DO SOME OTHER THING
    }
}

Пример кода 2 :

for (int i=0; i<n; ++i) {
    double[] array = calculateSomethingAndReturnAnArray(i);
    if (someFunctionOnArrays(array)) {
        // DO ONE THING
    } else {
        // DO SOME OTHER THING
    }
}

Здесь private double[] calculateSomethingAndReturnAnArray(int i) всегда возвращает массив одинаковой длины. У меня есть сильное отвращение к Code Sample 2 , потому что он создает новый массив для каждой итерации, когда он может просто перезаписать существующий массив. Тем не менее, я думаю, что это может быть один из тех случаев, когда я должен просто сидеть сложа руки и позволить Java справиться с ситуацией для меня.

По каким причинам предпочитаете один из способов другим, или они действительно идентичны в Java?

Ответы [ 3 ]

8 голосов
/ 02 сентября 2011

Здесь нет ничего особенного в массивах, потому что вы не выделяете массив, вы просто создаете новую переменную, это эквивалентно:

Object foo;
for(...){
    foo = func(...);
}

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

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

См. такжеэто аналогичный вопрос о лучших практиках .

1 голос
/ 02 сентября 2011

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

Таким образом, следующее с точки зрения семантики и производительности идентично:

double[] array;
for (int i=0; i<n; ++i) {
    array = calculateSomethingAndReturnAnArray(i);
    // ...
}

и

for (int i=0; i<n; ++i) {
    double[] array = calculateSomethingAndReturnAnArray(i);
    // ...
}

(Вы даже не можете отрицать, что первый случай позволяет использовать array после окончания цикла. Для того, чтобы это было допустимо, array должен иметь определенное значение после цикла, и он не ' t, если вы не добавите в объявление инициализатор, например double[] array = null;)


Чтобы развить точку зрения @Mark Elliot о микрооптимизации:

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

  • Даже если компилятор Java фактически выпустил некоторый нетривиальный исполняемый код для double[] array;, есть вероятность, что время выполнения будет незначительным по сравнению с общим временем выполнения тела цикла и приложения в целом. Следовательно, это, скорее всего, бессмысленная оптимизация.

  • Даже если это стоит оптимизации, вы должны учитывать, что вы оптимизировали ее для конкретной целевой платформы; то есть конкретное сочетание аппаратного обеспечения и версии JVM. Подобные микрооптимизации могут быть неоптимальными на других платформах и теоретически могут быть антиоптимизациями.

Таким образом, вы, скорее всего, тратите время впустую, если при написании кода Java сосредоточитесь на таких вещах. Если производительность является проблемой для вашего приложения, сфокусируйтесь на производительности на уровне MACRO; например такие вещи, как алгоритмическая сложность, хороший дизайн базы данных / запроса, шаблоны сетевых взаимодействий и т. д.

0 голосов
/ 02 сентября 2011

Оба создают новый массив для каждой итерации.У них одинаковая семантика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...