Вопрос-ответ

Declaring variables inside or outside of a loop

Объявление переменных внутри или вне цикла

Почему следующее работает нормально?

String str;
while (condition) {
str = calculateStr();
.....
}

Но говорят, что это опасно / некорректно:

while (condition) {
String str = calculateStr();
.....
}

Необходимо ли объявлять переменные вне цикла?

Переведено автоматически
Ответ 1

Область действия локальных переменных всегда должна быть как можно меньше.

В вашем примере, я полагаю, str это не используется вне while цикла, иначе вы бы не задавали вопрос, потому что объявлять его внутри while цикла было бы невозможно, поскольку это не скомпилировалось бы.

Итак, поскольку str не используется вне цикла, наименьшая возможная область для str находится внутри цикла while.

Итак, ответ заключается в том, что категорически это str должно быть объявлено в цикле while. Никаких "если", никаких "и", никаких "но".

Единственный случай, когда это правило может быть нарушено, - это если по какой-то причине жизненно важно, чтобы каждый такт был выжат из кода, и в этом случае вы могли бы рассмотреть возможность создания экземпляра чего-либо во внешней области видимости и повторного использования этого вместо повторного создания экземпляра на каждой итерации внутренней области видимости. Однако к вашему примеру это не относится из-за неизменяемости строк в java: новый экземпляр str всегда будет создаваться в начале вашего цикла, и его придется выбросить в конце, поэтому там нет возможности оптимизировать.

РЕДАКТИРОВАТЬ: (вставляя мой комментарий ниже в ответ)

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

Ответ 2

Я сравнил байт-код этих двух (похожих) примеров:

Давайте посмотрим на 1. пример:

package inside;

public class Test {
public static void main(String[] args) {
while(true){
String str = String.valueOf(System.currentTimeMillis());
System.out.println(str);
}
}
}

после javac Test.java, javap -c Test вы получите:

public class inside.Test extends java.lang.Object{
public inside.Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
3: invokestatic #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
6: astore_1
7: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
10: aload_1
11: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: goto 0

}

Давайте посмотрим на 2. пример:

package outside;

public class Test {
public static void main(String[] args) {
String str;
while(true){
str = String.valueOf(System.currentTimeMillis());
System.out.println(str);
}
}
}

после javac Test.java, javap -c Test вы получите:

public class outside.Test extends java.lang.Object{
public outside.Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
3: invokestatic #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
6: astore_1
7: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
10: aload_1
11: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: goto 0

}

Наблюдения показывают, что между этими двумя примерами нет разницы. Это результат спецификаций JVM...

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

Ответ 3

Объявление объектов в наименьшей области видимости улучшает удобочитаемость.

Производительность не имеет значения для современных компиляторов.(в этом сценарии)
С точки зрения обслуживания, 2-й вариант лучше.
Объявляйте и инициализируйте переменные в одном и том же месте, в максимально узкой области видимости.

Как сказал Дональд Эрвин Кнут:


"Мы должны забыть о небольшой эффективности, скажем, в 97% случаев: преждевременная оптимизация - корень всего зла"


т.е. Ситуация, когда программист позволяет соображениям производительности влиять на дизайн фрагмента кода. Это может привести к тому, что дизайн будет не таким чистым, каким мог бы быть, или неправильный код, потому что код усложняется из-за оптимизации, и программист отвлекается на оптимизацию.

Ответ 4

если вы хотите использовать str также outside looop; объявите его outside . в противном случае подойдет 2-я версия.

java