Чи має значення, якщо я оголошую змінні всередині або зовні циклу на 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
}

EDIT: з 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
У цьому випадку, очевидно, є продуктивність і штраф за пам'ять. Але це не зовсім так у запитанні ОП
Kemoda

1
Посилання розірвано.
Зон

1

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

Крім того, набагато кращим стилем є надання змінним якомога меншої області застосування. Це запобігає аваріям.


Це неправда - на рівні JVM немає обмеженого простору для локальних змінних.
Майкл Боргвардт

ти маєш на увазі, що якщо я напишу для (int i = ..) 1000 разів, на стеку буде 1000 різних змінних, коли я вийду з функції?
ddyer

відповідно до artima.com/insidejvm/ed2/jvm8.html "Наприклад, якщо дві локальні змінні мають обмежені діапазони, які не перетинаються, наприклад, локальні змінні i i j у Example3b, компілятори можуть використовувати той самий запис масиву для обох змінних. "І це має сенс, компілятори вільні оптимізувати розмір кадру стека таким чином.
ddyer

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