Java: создавать переменные в цикле: хороший или плохой стиль?

У меня был один простой вопрос. Обычно я пишу код следующим образом:

String myString = "hello";

for (int i=0, i<10; i++)
{
  myString = "hello again";
}

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

for (int i=0, i<10; i++)
{
  String myString = "hello again";
}

Это даже правильно? Или это тот случай, когда у Ive был явный объект, например объект из созданного мной класса? Что, если это было логическое или int? Что лучше стиль кодирования? Проинвестировать его один раз перед циклом и использовать его в цикле или создавать его каждый раз в цикле? И почему? Поскольку программа работает быстрее или меньше используется память или...?

Кто-то сказал мне, что если это логическое значение, я должен создать экземпляр непосредственно в цикле. Он сказал, что это не повлияет на кучу, и было бы более ясно, что переменная принадлежит внутри цикла. Итак, что правильно?

Спасибо за ответ!: -)

====

Спасибо за все ваши ответы!

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

Ответ 1

Нет, последний код на самом деле не действителен. Это было бы с фигурными скобками:

for (int i=0; i<10; i++)
{
    String myString = "hello again";
}

(В принципе вы не можете использовать объявление переменной как тело одного оператора для оператора if, цикл и т.д.)

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

Конечно, если вам нужно обратиться к переменной вне цикла (до или после), вам также нужно объявить ее вне цикла.

Вы должны различать переменные и объекты, когда считаете эффективность. В приведенном выше коде используется не более одного объекта - объект String, на который ссылается буквальный "привет снова".

Ответ 2

Как упоминалось в Binyamin Sharet, вы обычно хотите объявить переменную в пределах минимальной возможной области. В ваших конкретных примерах, второй, как правило, предпочтительнее, если вам не нужен доступ к переменной вне вашего цикла.

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

for (int i=0, i<1000; i++)
{
  String myString = new String("hello again"); // 1000 Strings are created--one on every iteration
  ...
}

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

String myString = new String("hello again"); // only one String is created

for (int i=0, i<1000; i++)
{
  ...
}

И, чтобы получить полный круг, вы можете вручную ограничить область, добавив дополнительные фигурные скобки вокруг соответствующего раздела кода:

{ // Limit the scope
  String myString = new String("hello again");

  for (int i=0, i<1000; i++)
  {
    ...
  }
}

Ответ 3

Похоже, вы имеете в виду declare, а не instantiate, и в целом вы должны объявить переменную в минимальной требуемой области (в данном случае - в цикле).

Ответ 4

если вы собираетесь использовать переменную за пределами цикла for, затем объявите ее стороной, иначе ее лучше сохранить минимальную область

Ответ 5

Проблема со вторым заключается в том, что вы создаете объект, а кто-то (GC) должен их очищать, конечно, для 10-итераций это неважно.

Кстати в вашем конкретном примере я бы написал

    String myString = null; 
    final String HELLO_AGAIN="hello again";
    for (int i=0; i<10; i++)
      myString = HELLO_AGAIN;

Ответ 6

Если значение не изменено, вы должны обязательно создать экземпляр вне цикла.

Ответ 7

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

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

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