我使用了一个常量来为数组分配空间。
之后,当我使用for循环访问数组中的每个位置时,我应该使用数组的.length值或声明期间使用的常量值来处理测试部分吗?
也就是说
for (int i = 0; i < array.length; i++)
或
for (int i = 0; i < constantArraySize; i++)
?
哪个更好?
考虑性能,没有一个应该比另一个更好。
考虑到可读性,您应该使用array.length
来明确希望遍历数组。所以我会选择第一个选项
由于数组的大小是固定的,所以使用哪一个并不重要。除非你修改了数组的引用。让我们看一下这个例子:
public class Test
{
final int SIZE = 3;
int[] arr;
public Test()
{
arr = new int[SIZE];
print();
arr = new int[SIZE - 1]; // modify
print();
}
public void print()
{
for (int i = 0; i < SIZE; i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args)
{
Test t = new Test();
}
}
输出:0
0
0
0
0
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at testpackage.Test.print(Test.java:19)
at testpackage.Test.<init>(Test.java:13)
at testpackage.Test.main(Test.java:25)
您将得到一个异常,因为您已将引用更改为较小大小的数组。如果你使用arr.length
,这个问题就不会发生。除非您确定不会修改arr
的引用,否则您可以使用常量
由于数组是不可变的(我的意思是它的长度不能改变),从功能的角度来看,这真的无关紧要。
从性能的角度来看,对局部变量和array.length
的访问也是相同的。
这可能很重要,例如,如果你有几个相同长度的数组,或者你有任何其他原因,使用array.length
在特定上下文中比使用特殊变量可读性差。
以上两个方法都不重要。
但如果有任何计算,
如
for(int i=0;i< (j*10+10);i++)
{
}
你应该将计算保存到一个变量中,并在条件
中使用它int temp=j*10+10;
for(int i=0;i<temp;i++)
{
}
代码优化
我认为你最好的选择是foreach:
for (Item item : array) {
// Do stuff
}
编译器会为您优化它,并且它更容易阅读。万岁!
优化,你说?确实。通常不会有什么不同,但如果它更容易阅读和更快,为什么不这样做呢?
考虑这个类:
final int SIZE = 3;
final String[] a = new String[SIZE];
void doStuff(String s){}
void useLength(){
for (int i = 0; i < a.length; i++) {
doStuff(a[i]);
}
}
void useConstant(){
for (int i = 0; i < SIZE; i++) {
doStuff(a[i]);
}
}
void useForEach(){
for (String s : a) {
doStuff(s);
}
}
对进行反编译,得到如下代码:
void useLength();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_0
4: getfield #4 // Field a:[Ljava/lang/String;
7: arraylength
8: if_icmpge 27
11: aload_0
12: aload_0
13: getfield #4 // Field a:[Ljava/lang/String;
16: iload_1
17: aaload
18: invokevirtual #5 // Method doStuff:(Ljava/lang/String;)V
21: iinc 1, 1
24: goto 2
27: return
因此,如果数组是一个字段,使用length
将在每次迭代中加载该字段两次。如果字段导致刷新(例如,如果它是易失的,或者JIT心情不好,等等),这可能会产生影响。如果封闭对象被并发线程访问,它也不是线程安全的(数组可以在op 7和op 17之间被更改)。
void useConstant();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_3
4: if_icmpge 23
7: aload_0
8: aload_0
9: getfield #4 // Field a:[Ljava/lang/String;
12: iload_1
13: aaload
14: invokevirtual #5 // Method doStuff:(Ljava/lang/String;)V
17: iinc 1, 1
20: goto 2
23: return
每次迭代只访问一个字段,但如果星型是正确的,它仍然会花费我们。如果字段改变值,它也有相当未指定的行为。
Foreach的操作略有不同:
void useForEach();
Code:
0: aload_0
1: getfield #4 // Field a:[Ljava/lang/String;
4: astore_1
5: aload_1
6: arraylength
7: istore_2
8: iconst_0
9: istore_3
10: iload_3
11: iload_2
12: if_icmpge 32
15: aload_1
16: iload_3
17: aaload
18: astore 4
20: aload_0
21: aload 4
23: invokevirtual #5 // Method doStuff:(Ljava/lang/String;)V
26: iinc 3, 1
29: goto 10
32: return
只有一个字段访问和一个数组长度检查!它大致相当于:
void useForEach(){
String[] localArr = arr;
for (int i = 0, length = arr.length; i < length; i++) {
doStuff(localArr[i]);
}
}