Java:在循环中实例化变量:好的还是坏的样式?

时间:2012-05-09 19:36:37

标签: java memory object coding-style heap

我有一个简单的问题。通常我会写这样的代码:

String myString = "hello";

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

因为我认为以下不是好的样式会导致它产生太多不必要的对象。

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

这是否正确?或者这就是我有一个像我创建的类中的对象这样的显式对象的情况?如果是boolean或int怎么办?什么是更好的编码风格?在循环之前实例化它一次并在循环中使用它或者每次在循环中实例化它?为什么?因为程序使用的速度更快或更少,或者......?

有人告诉我,如果它是布尔值,我应该直接在循环中实例化它。他说这对堆没有影响,而且变量属于循环内部会更清楚。那么什么是正确的?

谢谢你的回答! : - )

====

感谢您的所有答案!

总之:最好在尽可能小的范围内声明一个对象。通过声明和实例化循环外的对象没有性能改进,即使在每个循环中对象都被重新实例化。

7 个答案:

答案 0 :(得分:15)

不,后一个代码实际上并不有效。然而,这将是括号:

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

(基本上你不能将变量声明用作if语句的单语句体,循环等。)

对于第一个版本IMO来说,它是毫无意义的,但是有效 - 并且首选。它不需要更多的内存,但通常一个好主意是让你的局部变量尽可能缩小范围,尽可能晚地声明,理想情况下在同一点初始化。它使每个变量的使用位置更加清晰。

当然,如果你需要在循环之外(之前或之后)引用变量,那么你也需要在循环之外声明它。

在考虑效率时,您需要区分变量对象。上面的代码最多使用一个对象 - 文字“hello again”引用的String对象。

答案 1 :(得分:2)

正如Binyamin Sharet所提到的,您通常希望在尽可能小的范围内声明变量。在您的具体示例中,除非您需要访问循环外的变量,否则第二个示例通常更可取。

但是,在某些情况下,这可能会影响性能 - 即,如果您反复实例化同一个对象。在您的特定示例中,您将受益于Java自动汇集String文字。但是假设您实际上是在循环的每次迭代中创建同一对象的新实例,并且此循环正在执行数百次或数千次:

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++)
  {
    ...
  }
}

答案 2 :(得分:1)

好像你的意思是declare,而不是instantiate,一般来说,你应该在所需的最小范围内声明一个变量(在这种情况下 - 在循环中)。

答案 3 :(得分:1)

如果你打算在for循环之外使用变量,那么将它声明一边,否则最好将范围保持在最小值

答案 4 :(得分:1)

第二个问题是你创建对象而某人(GC)必须清理它们,当然10次迭代它并不重要。

BTW在您的具体示例中我会写

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

答案 5 :(得分:0)

除非更改值,否则绝对应该在循环外实例化。

答案 6 :(得分:0)

这里的问题是String是一个不可变对象:你不能改变字符串的值,只有你可以创建新的String对象。无论哪种方式,如果您的目标是为变量分配一个新的对象实例,那么限制您的范围并将其声明在循环体内。

如果您的对象是可变的,那么在循环的每个下一次迭代中重用该对象是合理的,只需更改您需要的那些属性即可。此概念用于多次运行相同的查询,但使用不同的参数,您可以使用PreparedStatement。

在极端情况下,您甚至可以维护可在整个应用程序中共享的对象池。在资源不足时创建其他对象,如果检测到合理的非使用量,则会缩小。此概念用于维护连接池。