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"; } 

这甚至是正确的吗? 或者就是这种情况,当我有一个显式对象,如我创建的类中的对象? 如果是boolean或int怎么办? 什么是更好的编码风格? 在循环之前将它实例化一次并在循环中使用它或者每次在循环中实例化它? 为什么? 因为程序更快或更少使用存储或…?

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

谢谢你的回答! 🙂

====

谢谢你的所有答案!

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

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

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

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

这将是毫无意义的,但有效 - 并且第一版IMO 更可取 。 它不需要更多的内存,但通常一个好主意是将局部变量放在尽可能最窄的范围内,尽可能晚地声明,理想情况下在同一点进行初始化。 它使每个变量的使用位置更加清晰。

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

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

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

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

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

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

顺便提一下,在你的具体例子中我会写的

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

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

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

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

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