Java中按原语或装箱类的foreach循环

Java中按原语或装箱类的foreach循环,java,generics,collections,boxing,unboxing,Java,Generics,Collections,Boxing,Unboxing,目前我正在阅读一本书“Java泛型和集合”,我发现了一个有趣的代码: List<Integer> ints = Arrays.asList(1,2,3); int s = 0; for (int n : ints) { s += n; } assert s == 6; 但是,Eclipse IDE建议我迭代装箱类型: for (Integer n : ints) { ... } 使用一种或另一种迭代方式有什么好处吗?装箱/取消装箱在运行时是有代价的 如果像您一样在循环体中取消对

目前我正在阅读一本书“Java泛型和集合”,我发现了一个有趣的代码:

List<Integer> ints = Arrays.asList(1,2,3);
int s = 0;
for (int n : ints) { s += n; }
assert s == 6;
但是,Eclipse IDE建议我迭代装箱类型:

for (Integer n : ints) { ... }

使用一种或另一种迭代方式有什么好处吗?

装箱/取消装箱在运行时是有代价的

  • 如果像您一样在循环体中取消对
    整数的装箱,则不会有太大区别
  • 如果在循环体中多次取消对
    整数的装箱,最好使用
    for(inti:ints)
  • 如果要在循环体中使用整数,那么使用
    int
    将导致不必要的unbox/box操作
例如:

List<Integer> subList = new ArrayList<>();

for (Integer i : ints) { //better not to unbox
  if (someCondition(i)) subList.add(i);
}

for (int i : ints) { //better to unbox once
  int a = i;
  int b = 2 * i;
  sum += a + b - i;
}
List subList=new ArrayList();
对于(整数i:ints){//最好不要取消装箱
if(someCondition(i))子列表添加(i);
}
对于(inti:ints){//最好取消装箱一次
int a=i;
int b=2*i;
总和+=a+b-i;
}

装箱/拆箱在运行时有成本

  • 如果像您一样在循环体中取消对
    整数的装箱,则不会有太大区别
  • 如果在循环体中多次取消对
    整数的装箱,最好使用
    for(inti:ints)
  • 如果要在循环体中使用整数,那么使用
    int
    将导致不必要的unbox/box操作
例如:

List<Integer> subList = new ArrayList<>();

for (Integer i : ints) { //better not to unbox
  if (someCondition(i)) subList.add(i);
}

for (int i : ints) { //better to unbox once
  int a = i;
  int b = 2 * i;
  sum += a + b - i;
}
List subList=new ArrayList();
对于(整数i:ints){//最好不要取消装箱
if(someCondition(i))子列表添加(i);
}
对于(inti:ints){//最好取消装箱一次
int a=i;
int b=2*i;
总和+=a+b-i;
}

所以,在下面的代码中

    for (int n : ints) // in every loop ints current index value which is an Integer is unboxed and assigned to 'int n'
当读取以下代码时

     s += n;// int n is added to int s (primitive added to primitive ie; no conversion done here)
2)现在是第二种方法

    for (Integer n : ints) { ... }// here, since 'n' is also boxed so no conversion takes place
但是,当遇到以下行时

    s += n; // boxed Integer n is unboxed to a primitive and added to primitive 's' (so unboxing/conversion happens in each addition)
这就是两者之间的区别,然而,两种方法中的转换次数是相同的

是的

所以,在下面的代码中

    for (int n : ints) // in every loop ints current index value which is an Integer is unboxed and assigned to 'int n'
当读取以下代码时

     s += n;// int n is added to int s (primitive added to primitive ie; no conversion done here)
2)现在是第二种方法

    for (Integer n : ints) { ... }// here, since 'n' is also boxed so no conversion takes place
但是,当遇到以下行时

    s += n; // boxed Integer n is unboxed to a primitive and added to primitive 's' (so unboxing/conversion happens in each addition)

这就是两者之间的区别,然而,两种方法中的转换次数是相同的

集合不支持基元类型,因此集合中有包装类可使用基元。泛型在运行时被删除,因此列表中填充了对象。在检索时,它们被转换回
整数
。当您使用
int
值在列表上迭代时,会强制对每次迭代执行取消装箱。集合不支持基元类型,因此集合中有包装类使用基元。泛型在运行时被删除,因此列表中填充了对象。在检索时,它们被转换回
整数
。当您使用
int
值在列表上迭代时,每次迭代都会强制取消装箱。如果您使用
int
而不是
Integer
,那么如果集合的大小很大,它也会导致更快的执行。您的答案很有用,但是如果循环中有很多地方是“Integer i”呢是否要取消装箱(例如,总和与其他算术运算一起计算)?是不是最好用于(int n:int)?@DmytroPlekhotkin在这种情况下,最好用
为(int i:int)
取消一次装箱当然。@Prashant我不明白你的意思。无论集合的大小,从不取消对整数的绑定都比取消对其绑定好…@Prashant Ah ok-但这是另一种讨论:如果您想使用JDK的集合之一,除了使用整数,您别无选择。如果你想坚持使用整数,你必须使用另一个库或返回数组。如果你使用的是
int
而不是
Integer
,那么如果集合的大小很大,它也会导致更快的执行。你的答案很有用,但是如果在循环中有很多地方“Integer i”将被取消绑定呢(例如,总和与其他算术运算一起计算)?是否最好用于(int n:int)?@DmytroPlekhotkin在这种情况下,最好使用
对(int i:int)取消装箱一次
当然。@Prashant我不明白你的意思。无论集合的大小,永远不要取消对整数的装箱总比取消装箱好…@Prashant啊,好吧-但这是另一种讨论:如果你想使用JDK的集合,你除了使用整数别无选择。如果你想坚持整数,你必须使用其他库或返回阵列。