Имеет ли значение, если я объявляю переменные внутри или вне цикла в Java? [закрыто]

13

Возможный дубликат:
где вы объявляете переменные? Вершина метода или когда они вам нужны?

Имеет ли значение, если я объявляю переменные внутри или вне цикла в Java?

Это

for(int i = 0; i < 1000; i++) {
   int temp = doSomething();
   someMethod(temp);
}

равно этому (в отношении использования памяти)?

int temp = 0;
for(int i = 0; i < 1000; i++) {
   temp = doSomething();
   someMethod(temp);
}

А что, если временная переменная, например, ArrayList?

for(int i = 0; i < 1000; i++) {
   ArrayList<Integer> array = new ArrayList<Integer>();
   fillArray(array);
   // do something with the array
}

РЕДАКТИРОВАТЬ: с javap -cя получил следующий вывод

Переменная вне цикла:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iconst_0      
       3: istore_2      
       4: iload_2       
       5: sipush        1000
       8: if_icmpge     25
      11: invokestatic  #2                  // Method doSomething:()I
      14: istore_1      
      15: iload_1       
      16: invokestatic  #3                  // Method someMethod:(I)V
      19: iinc          2, 1
      22: goto          4
      25: return  

Переменная внутри цикла:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     23
       9: invokestatic  #2                  // Method doSomething:()I
      12: istore_2      
      13: iload_2       
      14: invokestatic  #3                  // Method someMethod:(I)V
      17: iinc          1, 1
      20: goto          2
      23: return        

А для интересующихся этот код:

public class Test3 {
    public static void main(String[] args) {
        for(int i = 0; i< 1000; i++) {
            someMethod(doSomething());
        }   
    }
    private static int doSomething() {
        return 1;
    }
    private static void someMethod(int temp) {
        temp++;
    }
}

производит это:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     21
       9: invokestatic  #2                  // Method doSomething:()I
      12: invokestatic  #3                  // Method someMethod:(I)V
      15: iinc          1, 1
      18: goto          2
      21: return   

Но тогда оптимизация происходит во время выполнения. Есть ли способ посмотреть на оптимизированный код? (Простите за долгое редактирование)

Puckl
источник
1
Я рад, что вы на самом деле посмотрели на разборку и надеюсь, что она вас чему-то научила. Я надеялся, что кто-то, имеющий реальный опыт работы с Java, ответит на ваш последний вопрос об оптимизированном коде, но, возможно, вы можете опубликовать эту конкретную часть в Stackoverflow - кажется, это очень конкретный вопрос.
Йорис Тиммерманс
Да, я постараюсь получить оптимизированный код. (Вопрос немного изменился, я спросил это с оптимизированным кодом в редактировании)
Puckl
Неработающая ссылка на Дубликат. Пришло время сделать этот вопрос оригинальным.
Зон

Ответы:

4

Общий ответ на большинство из этих вопросов должен быть «почему бы вам не попробовать и выяснить?». В Java вы, вероятно, могли бы взглянуть на сгенерированный байт-код (я считаю, что инструмент называется javap), чтобы увидеть, в чем разница в байт-коде между этими двумя способами объявления переменной.

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

Йорис Тиммерманс
источник
3

Краткий ответ: нет. Подобные вопросы уже были где-то на этом сайте. Нет заметного различия согласно сгенерированному байт-коду. Объявление их при необходимости дает меньше строк кода

Вот принятый ответ: /software//a/56590/43451

Kemoda
источник
Как насчет производительности, когда вы создаете новый объект внутри цикла, который также может быть создан только один раз?
Bubblewrap
3
В этом случае очевидно, что производительность и потеря памяти. Но это не совсем так в вопросе оп
Кемода
1
Ссылка не работает.
Зон
1

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

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

ddyer
источник
Это не так - на уровне JVM нет такой вещи, как ограниченная область действия для локальных переменных.
Майкл Боргвардт
Вы имеете в виду, что если я напишу для (int i = ..) 1000 раз, в стеке при выходе из функции будет 1000 разных переменных?
ddyer
в соответствии с artima.com/insidejvm/ed2/jvm8.html "Например, если две локальные переменные имеют ограниченные области видимости, которые не перекрываются, такие как локальные переменные i и j в Example3b, компиляторы могут использовать одну и ту же запись массива для обеих переменных. "И это имеет смысл, компиляторы могут оптимизировать размер фрейма стека таким образом.
ddyer
1
Хорошая точка зрения; но если мы говорим об оптимизации компилятора, то компилятор может почти так же легко повторно использовать записи локальных переменных для переменных, которые имеют перекрывающуюся лексическую область, но не используются перекрывающимся образом.
Майкл Боргвардт