在循环内部或外部声明变量

280

为什么下面的代码可以正常工作?

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

但是这个被认为是危险/不正确的:

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

在循环外声明变量是必要的吗?


1
这个回答解决了你的问题吗?在循环之前或之中声明变量的区别? - user202729
20个回答

3

3
根据Google Android开发指南,变量作用域应该被限制。请查看此链接:Limit Variable Scope

2
正如许多人所指出的那样,
String str;
while(condition){
    str = calculateStr();
    .....
}

这并比这个更好:

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

所以如果您不会重复使用变量,就不要在其作用域外声明变量...

1
除非可能以这种方式:[链接] (https://dev59.com/eFfUa4cB1Zd3GeqPJZaW#22245471) - Dainius Kreivys

1

在循环内部声明会限制相应变量的作用域。这完全取决于项目对变量作用域的需求。


1

确实,上述问题是一个编程问题。您想如何编写代码?您需要在哪里访问“STR”?声明仅在本地使用的变量作为全局变量是没有用处的。我认为这是编程的基础。


0

这两个例子得到的结果是相同的。然而,第一个让你可以在 while 循环之外使用 str 变量;而第二个则不行。


0

我认为对象的大小也很重要。 在我的一个项目中,我们声明并初始化了一个大型的二维数组,导致应用程序抛出了内存不足异常。 我们将声明移到了循环外,并在每次迭代开始时清空了数组。


0

即使在执行下面的代码后,str变量仍将可用并保留一些内存空间。

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

在下面的代码中,str变量将不可用,并且为str变量分配的内存也将被释放。

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

如果我们遵循第二种方法,肯定会减少系统内存并提高性能。


-1
几乎所有人都需要注意:这里有一段示例代码,在循环内部,使用 Java 7 可能会比我的电脑慢200倍(内存消耗也略有不同)。但这与分配有关,而不仅仅是作用域。
public class Test
{
    private final static int STUFF_SIZE = 512;
    private final static long LOOP = 10000000l;

    private static class Foo
    {
        private long[] bigStuff = new long[STUFF_SIZE];

        public Foo(long value)
        {
            setValue(value);
        }

        public void setValue(long value)
        {
            // Putting value in a random place.
            bigStuff[(int) (value % STUFF_SIZE)] = value;
        }

        public long getValue()
        {
            // Retrieving whatever value.
            return bigStuff[STUFF_SIZE / 2];
        }
    }

    public static long test1()
    {
        long total = 0;

        for (long i = 0; i < LOOP; i++)
        {
            Foo foo = new Foo(i);
            total += foo.getValue();
        }

        return total;
    }

    public static long test2()
    {
        long total = 0;

        Foo foo = new Foo(0);
        for (long i = 0; i < LOOP; i++)
        {
            foo.setValue(i);
            total += foo.getValue();
        }

        return total;
    }

    public static void main(String[] args)
    {
        long start;

        start = System.currentTimeMillis();
        test1();
        System.out.println(System.currentTimeMillis() - start);

        start = System.currentTimeMillis();
        test2();
        System.out.println(System.currentTimeMillis() - start);
    }
}

结论:根据本地变量的大小,差异可能会很大,即使变量不是很大。
只是想说有时候,循环内外确实很重要。

2
当然,第二个更快,但你正在做不同的事情:test1正在创建许多具有大数组的Foo对象,而test2则没有。test2一遍又一遍地重复使用相同的Foo对象,在多线程环境中可能是危险的。 - Hardcoded
在多线程环境中是危险的吗?请解释原因。我们正在谈论一个局部变量。它在每次方法调用时都会被创建。 - rt15
如果您将Foo对象传递给一个异步处理数据的操作,那么当您在其中更改数据时,该操作可能仍在处理Foo实例。即使没有多线程也可能产生副作用。因此,在不知道谁仍在使用实例时,实例重用是非常危险的。 - Hardcoded
Ps:你的setValue方法应该是bigStuff[(int) (value % STUFF_SIZE)] = value;(尝试一个值为2147483649L的例子) - Hardcoded
谈到副作用:你比较过你的方法的结果了吗? - Hardcoded
是的,有副作用。我的观点是,有时候,如果你在循环中实例化一个大对象(即使不是那么大:512个长整型...),有时候以不同的方式编码并重复使用相同的实例会更快。显然,为了能够这样做,该实例必须是可重用的。 - rt15

-2

如果你的calculateStr()方法返回null,然后你试图在str上调用一个方法,那么你就有了NullPointerException的风险。

更一般地说,避免使用值为null的变量。顺便说一下,对于类属性来说,这更加重要。


2
这与问题无关。NullPointerException(对未来函数调用)的概率不会取决于变量声明的方式。 - Desert Ice
1
我不这么认为,因为问题是“最好的方法是什么?”在我看来,我更喜欢更安全的代码。 - Rémi Doolaeghe
1
这段代码不存在NullPointerException的风险。如果这段代码尝试执行return str;,它将会遇到编译错误。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接