Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否为每个“循环”计算循环条件;至于;Java中的句子?_Java_Optimization_Loops - Fatal编程技术网

是否为每个“循环”计算循环条件;至于;Java中的句子?

是否为每个“循环”计算循环条件;至于;Java中的句子?,java,optimization,loops,Java,Optimization,Loops,这是我的Java代码: List<Object> objects = new ArrayList(); // Assign values to objects ... for (int i = 0; i < objects.size(); i++) { Object object = objects.get(i); ... } List objects=new ArrayList(); //为对象指定值 ... 对于(int i=0;i

这是我的Java代码:

List<Object> objects = new ArrayList();

// Assign values to objects
...

for (int i = 0; i < objects.size(); i++) {
    Object object = objects.get(i);
    ...
}
List objects=new ArrayList();
//为对象指定值
...
对于(int i=0;i
我有两个问题:

  • 在声明循环之前,
    objects.size()
    是只计算一次,还是每个循环都计算一次
  • 如果每个循环都计算了
    objects.size()
    ,那么如果其他线程在没有多线程保护的情况下同时更改它,代码可能会崩溃
    我说的对吗?

    是的,每次都计算。如果有另一个线程更改对象列表的大小,则循环条件将不断更改。

    当您在每次计算的循环条件内使用
    objects.size()
    时,是。更好的方法是在进入循环之前将其保存在变量中; 像int

     limit=objects.size(); 
     for (int i = 0; i < limit; i++) {
        Object object = objects.get(i);
     ...
     }
    
    limit=objects.size();
    对于(int i=0;i
    如果您有另一个线程,它可能会更改它,但使用上述选项,它不会影响或使您的程序崩溃。

    答案:

  • objects.size()
    在每个循环中都被调用(是否计算取决于ArrayList实现,您不应该关心它)
  • 是的,另一个线程可能会更改列表,这将影响您的循环
  • 真正的答案:

    你不必在意,以下是你不必在意的方式:

  • 使用线程安全的。如果使用迭代器(foreach语法在内部使用)对其进行迭代,则会像迭代开始时一样对列表进行迭代
  • 使用
    foreach
    语法,这意味着您不必使用索引等-这已经为您完成了:

  • 是的,每次都会计算

    如果查看for循环语句,它将在第一个语句中设置计数器初始值 然后它将检查最大值,然后它将执行循环体,然后它将增加计数器的值,然后再次检查最大值。每次检查最大值时,它都会调用size方法

  • objects.size()是在声明循环之前只计算一次,还是每次循环都计算一次
  • 每一次

  • 如果每个循环都计算objects.size(),那么如果其他线程在没有多线程保护的情况下同时更改它,代码可能会崩溃
  • 对。或者至少,您可能会遇到一个
    ConcurrentModificationException
    ,并且没有任何合理的方法来处理它

    请注意,即使缓存了
    对象.size()
    ,也可能会发生这种情况,但现在
    .get()
    将失败,因为您试图获取一个不再存在的索引
    objects.size()
    由于从容器中删除或添加了某些内容而发生更改


    在迭代集合时不要修改它们。

    从概念上讲,可以对每个循环计算objects.size()。但是,由于该方法很短,因此可以将其内联并缓存为非易失变量。i、 e.另一个线程可以改变它,但不能保证如果它改变了,你会看到改变

    保存大小的一个简单方法是使用以下命令

    for (int i = 0, size = objects.size(); i < size; i++) {
        Object object = objects.get(i);
    ...
    }
    
    for(int i=0,size=objects.size();i
    但是,如果您担心另一个线程可能会更改大小,则此方法仅在添加对象时保护您。如果删除了某个对象,当您尝试访问现在超出列表末尾的值时,仍然会出现异常


    使用CopyOnWriteArrayList可以避免这些问题(如果您使用迭代器),但会使写入变得更昂贵。

    这当然假设对象的大小不变,这完全忽略了第二个问题,因此您可以使用Bohemian提供的选项。对于大多数类,您可能不会得到
    ConcurrentModificationException
    ,因为您尚未打开
    迭代器。CME通常只有在打开迭代器,然后修改集合(迭代器提供的方法除外),然后再次尝试使用相同的迭代器时才会出现。例如,如果这个
    ArrayList
    被包装在一个
    Collections.synchronizedList
    中,那么这个代码就可以正常工作了——只不过你会遇到一个竞争条件,在这个条件下,你可能会以一个IndexOutOfBoundsException结束。呃,是的。抱歉,我习惯于看到人们以现代的方式进行迭代,而通常使用Python:)@KarlKnectel Java也有这些现代的方式!:)
    for(objectobj:objects){…}
    这是打开并使用
    迭代器的语法糖,因此可以肯定地抛出CME。我在数组列表中为每个循环添加了一个新项&它不会因为CME而崩溃。不是每个人都在内部使用迭代器吗?
    
    for (int i = 0, size = objects.size(); i < size; i++) {
        Object object = objects.get(i);
    ...
    }