变量声明在循环体内还是循环体外的争论

(1)

for (int i = 0; i < 10000; ++i) {
    Object obj = new Object();
    System.out.println("obj= "+ obj);
}

应改成
(2)

Object obj = null;
for (int i = 0; i < 10000; ++i) {
    obj = new Object();
    System.out.println("obj= "+ obj);
}

  今天想对“变量声明在循环体外合适还是循环体内合适?”这个命题吐槽一番,并且我有两个前提:1、变量的生命周期仅限于循环体。2、仅限于Java语言。

从我迄今为止待过的两家公司来说,他们的答案都是“变量要声明在循环体外部”。why?我猜想制定这个规矩的人也许是个C/C++程序员。众所周知,C/C++是手工管理内存的语言。这些程序员通常站在机器的角度考虑,视效率为生命。固有的思维决定了,即使他们清楚明白地知道,Java是具有垃圾回收功能的语言,也不惜一切将变量声明在循环体外。看到别人将声明写在了循环体内部,他们会特别变扭,吃不下睡不着。

看了上面的文字,我的观点不言而喻,我赞成将变量声明在循环体内部。why?

1、Java是一种具有垃圾回收功能的语言,并且随着版本的提高,如今的GC已经变得越来越smart。每次循环声明创建的变量,在本次循环结束之后即会被标记为“可以被GC回收了”。即使我知道Java的垃圾回收线程优先级相当低,也许在被标记为“可以被回收”后,这些内存空间并不能马上被真正的释放。

2、声明在循环体外部的变量,人为地将其的声明周期拉长了。这可不是件什么好事。回收的时间被推后了不说,更将严重的后果可能是,原本就应该“不可达”的引用被有意无意的再次使用了。这事非常糟糕的事。也许数据就这么被破坏了,兴许你根本就没有意识到这事,这种隐性的bug将大大增加。

3、将变量声明在循环体外的做法也许节省不了多少空间。人说,没有实践就没有发言权。我真没试过这两种方式的效率区别到底有多大。可今天还是擅自揣测一下。我们知道,声明一个变量,并创建一个引用类型的对象赋值给这个变量。结果就是,在栈中开辟空间存放这个变量的引用本身,在堆中开辟空间存放“实实在在的对象”。因此,在循环体外部声明变量的方式,多多少少会节省一些栈空间,堆空间还是实实在在一点不打折。但是,相对于堆空间而言,栈空间真的只是九牛一毛罢了,所占比重真的很小。

4、Java的“foreach”循环。这个循环的写法例如for(Person p : personList),明显的这就是使用的在循环体内声明变量的方式。这是在JDK5之后,所推崇的遍历方式,为什么要推崇这种方式,不解释。

总之,将变量声明在循环体外的方式多少能节省点空间,可是带来的变量声明周期变长,回收时间推后以及更加严重的隐性bug危险等问题很多。比较而言,有些得不偿失了。

  事实上在Java的GC机制中如果一个对象有着具体的引用,那么是不会被GC自动回收的。 也就是说: Object obj = new Object();//写在100个循环内等于你有100个引用对应了100个对象 所以100个对象在一段时间内都是会占用内存,直到内存不足GC主动回收 obj = new Object();//写在100个循环内等于你使用1个引用分别100次调用了100个对象 所以当后一个对象init后,前一个对象已经是“无引用状态”,会很快的被GC自动回收 (在你的循环还未结束时,可能已经进行了多次GC回收,这点很重要) 也就是说第二种方法能更好的管理内存。

  Java高性能编程就是通过程序员对代码的掌控更切合计算机的识别与效率, 如果题主觉得安全更重要(但我没想到会有什么安全问题)那也可以按照你的方法, 毕竟时代在进步,编程也没必要按部就班,能实现功能、保证效率就好。

  首先,变量的声明是在栈中进行的,而实例化则是在堆中,故栈中只有基础数据与实例的引用。

  故上面程序的不同点:
  1、在外面的定义的变量,只在栈中声明了一次。
  2、在里面的定义的变量,循环多少次就在栈中声明了多少次。
  3、在内存或说资源节省方面,肯定是在外面定义较好,是摧荐的写法;但是如果循环数不大,其实也者体现出来的差别也不大。
  4、由于实例化的对象都在堆中,故个人认为以上两个基本一样。

原文地址:https://www.cnblogs.com/fightingtong/p/9582008.html

时间: 2024-12-15 13:35:25

变量声明在循环体内还是循环体外的争论的相关文章

JAVA变量声明在循环体内还是循环体外

(1) for (int i = 0; i < 10000; ++i) { Object obj = new Object(); System.out.println("obj= "+ obj); } (2) Object obj = null; for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 在循环体外,始终都是这一个对象

java循环创建对象应该在循环体内还是循环体外

第一种: for(int i = 0; i < 100; i++) { Object obj = new Object() } 第二种: Object obj = null for(int i = 0; i < 10000; i++) { obj = new Object() } 第一次: Object obj = new Object();//写在100个循环内等于你有100个引用对应了100个对象 所以100个对象在一段时间内都是会占用内存,直到内存不足GC主动回收. 第二次: obj =

【python3之变量,输入输出,判断,循环】

一.python的基础语法和规则 1.变量 ①.变量的命名规则 语法: (下划线或字母)+(任意数目的字母.数字或下划线) 变量名必须以下划线或字母开头,而后面接任意数目的字母.数字或下划线.下划线分割. 区分大小写: SPAM和spam不同 不能使用python内置关键字,以下关键字不能声明为变量名 ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exe

【python的变量,输入输出,判断,循环】

一.python的基础语法和规则 1.变量 ①.变量的命名规则 语法: (下划线或字母)+(任意数目的字母.数字或下划线) 变量名必须以下划线或字母开头,而后面接任意数目的字母.数字或下划线.下划线分割. 区分大小写: SPAM和spam不同 不能使用python内置关键字,以下关键字不能声明为变量名 ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exe

SQL连接查询、变量、运算符、分支、循环语句

连接查询:通过连接运算符可以实现多个表查询.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 常用的两个链接运算符: 1.join   on 2.union 在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中.当检索数据时,通过连接操作查询出存放在多个表中的不同实体的信息.连接操作给用户带来很大的灵活性,他们可以在任何时候增加新的数据类型.为不同实体创建新的表,随后通过连接进行查询. 示例一: 示例二: 示例三: 示例四:

C++在循环内和循环外定义变量的差异(如何写出高效的for循环)

写这篇文章的原因是我在问答平台看到的一个问题: C++内层循环中定义变量和在外面定义比影响大吗? 问题来自:http://ask.csdn.net/questions/176270 例如: for(int i=0;i<999;i++) { for(int j=0;j<999;j++); } 内层循环每次都定义j会造成多大的消耗呢? 此处我给出的回答是: 这个需要看你具体用什么编译器.不过主流编译器(如vs和gcc)这一块优化都比较好,不会反复分配变量. 看到答案和评论,好像有很多人对这个感兴趣

【读阿里规约有感】循环体内的字符串连接时,使用StringBuilder的append()和+String的方式比较

阿里规约里原话是: [推荐]循环体内,字符串的连接方式,请使用 StringBuilder 的 append 方法进行扩展.(而不要用+String的方式)说明:因为反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费. 从这句话得知,用StringBuilder连接字符串比 + 的方式好,因为更少占用内存资源.可是我们怎么才能更加直观的看到性能对比呢? 这时

python中for循环中的循环变量

废话不多说,代码伺候: for i in range(3): print("hello") print(i) 运行结果如下: 从上面的例子可以看出,for循环里面的循环变量i作用域衍生到循环外面了.说明循环变量i,在遍历完之后值并没有消失,而是保留了最后一个变量的值,而且会覆盖之前变量的值!所以平时在使用的时候变量最好别和模块其他变量重复,否则可能出问题! 原文地址:https://www.cnblogs.com/xiaohaodeboke/p/12128829.html

JS中的循环结构、循环嵌套以及函数介绍

[循环结构的步骤]    *①声明循环变量    *②判断循环条件    *③执行循环体(while的{}中的所有代码)操作     *④更新循环变量    *     * 然后,循环执行②③④    *     *     * [JS中循环条件支持的数据类型]    * ①boolean:true 真     false   假    * ②string: 非空字符串为真       空字符串为假    * ③null/NaN/undefined:  全为假    * ④object:全为真