Имеет ли значение, если я объявляю переменные внутри или вне цикла в 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   

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


1
Я рад, что вы на самом деле посмотрели на разборку и надеюсь, что она вас чему-то научила. Я надеялся, что кто-то, имеющий реальный опыт работы с Java, ответит на ваш последний вопрос об оптимизированном коде, но, возможно, вы можете опубликовать эту конкретную часть в Stackoverflow - кажется, это очень конкретный вопрос.
— Йорис Тиммерманс

Да, я постараюсь получить оптимизированный код. (Вопрос немного изменился, я спросил это с оптимизированным кодом в редактировании)
— Puckl

Неработающая ссылка на Дубликат. Пришло время сделать этот вопрос оригинальным.
— Зон

Ответы:


4

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

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


3

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

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


Как насчет производительности, когда вы создаете новый объект внутри цикла, который также может быть создан только один раз?
— Bubblewrap

3
В этом случае очевидно, что производительность и потеря памяти. Но это не совсем так в вопросе оп
— Кемода

1
Ссылка не работает.
— Зон

1

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

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


Это не так - на уровне JVM нет такой вещи, как ограниченная область действия для локальных переменных.
— Майкл Боргвардт

Вы имеете в виду, что если я напишу для (int i = ..) 1000 раз, в стеке при выходе из функции будет 1000 разных переменных?
— ddyer

в соответствии с artima.com/insidejvm/ed2/jvm8.html "Например, если две локальные переменные имеют ограниченные области видимости, которые не перекрываются, такие как локальные переменные i и j в Example3b, компиляторы могут использовать одну и ту же запись массива для обеих переменных. "И это имеет смысл, компиляторы могут оптимизировать размер фрейма стека таким образом.
— ddyer

1
Хорошая точка зрения; но если мы говорим об оптимизации компилятора, то компилятор может почти так же легко повторно использовать записи локальных переменных для переменных, которые имеют перекрывающуюся лексическую область, но не используются перекрывающимся образом.
— Майкл Боргвардт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.