Второй - это то, что я бы предпочел. Функциональной разницы нет, кроме области обзора.
Установка одной и той же переменной на каждой итерации не имеет значения, потому что Integer
является неизменным классом. Теперь, если вы были , изменяя объект вместо того, чтобы создавать новый каждый раз, тогда будет разница.
И как примечание стороны, в этом коде вы должны использовать int
и Integer.parseInt()
, а не Integer
и Integer.parse()
. Вы вводите довольно много ненужного бокса и распаковки.
Edit: Это было некоторое время, так как я сброшенные вокруг в байткод, поэтому я думал, что мои руки грязные снова.
Вот тестовый класс я составил:
class ScopeTest {
public void outside(String[] args) {
Integer total = 0;
Integer i;
for (String str : args)
{
i = Integer.valueOf(str);
total += i;
}
}
public void inside(String[] args) {
Integer total = 0;
for (String str : args)
{
Integer i = Integer.valueOf(str);
total += i;
}
}
}
выход Bytecode (получен с javap -c ScopeTest
после компиляции):
Compiled from "ScopeTest.java"
class ScopeTest extends java.lang.Object{
ScopeTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public void outside(java.lang.String[]);
Code:
0: iconst_0
1: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_2
5: aload_1
6: astore 4
8: aload 4
10: arraylength
11: istore 5
13: iconst_0
14: istore 6
16: iload 6
18: iload 5
20: if_icmpge 55
23: aload 4
25: iload 6
27: aaload
28: astore 7
30: aload 7
32: invokestatic #3; //Method java/lang/Integer.valueOf:(Ljava/lang/String;)Ljava/lang/Integer;
35: astore_3
36: aload_2
37: invokevirtual #4; //Method java/lang/Integer.intValue:()I
40: aload_3
41: invokevirtual #4; //Method java/lang/Integer.intValue:()I
44: iadd
45: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
48: astore_2
49: iinc 6, 1
52: goto 16
55: return
public void inside(java.lang.String[]);
Code:
0: iconst_0
1: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_2
5: aload_1
6: astore_3
7: aload_3
8: arraylength
9: istore 4
11: iconst_0
12: istore 5
14: iload 5
16: iload 4
18: if_icmpge 54
21: aload_3
22: iload 5
24: aaload
25: astore 6
27: aload 6
29: invokestatic #3; //Method java/lang/Integer.valueOf:(Ljava/lang/String;)Ljava/lang/Integer;
32: astore 7
34: aload_2
35: invokevirtual #4; //Method java/lang/Integer.intValue:()I
38: aload 7
40: invokevirtual #4; //Method java/lang/Integer.intValue:()I
43: iadd
44: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
47: astore_2
48: iinc 5, 1
51: goto 14
54: return
}
Вопреки моим ожиданиям, была одна разница между ними: в outside()
, переменная i
по-прежнему занимала регистр, даже если она была опущена из фактического кода (обратите внимание, что все команды iload
и istore
указывают один регистр выше).
Компилятор JIT должен сделать короткую работу с этой разницей, но все же вы можете видеть, что ограничение области действия является хорошей практикой.
(Что касается моей предыдущей заметки, вы можете увидеть, что для добавления двух объектов Integer Java необходимо распаковать как с intValue
, так и добавить новое целое число с valueOf
. Не делайте этого, если абсолютно необходимо, потому что это бессмысленно и медленнее.)
Я предполагаю, что ваш фактический цикл более сложный, чем ваш образец, и на самом деле делает использование i другим, чем временная переменная или что-то в этом роде. – BoltClock
Почему вы используете дорогой Integer вместо int в первую очередь? – bmargulies
Я предлагаю вам задать вопрос таким образом, чтобы сосредоточиться на том, что вы хотите узнать. Существует так много неэффективности в примере с бокс, unboxing и 'new' в Integer, что, безусловно, переполняет любую теоретическую микро-оптимизацию в отношении области действия переменной. – Yishai