使用标志或if子句更有效率吗?

在Java循环中,使用boolean标志而不是if语句会更高效吗?

看看这两位代码。

使用标志:

public boolean isSomethingForAnyone() {
    boolean flag = false;
    for (Item item : listOfItems) {
        flag = flag || item.isSomething();
    }
    return flag;
}

使用if语句:

public boolean isSomethingForAnyone() {
    for (Item item : listOfItems) {
        if (item.isSomething())
            return true;
    }
    return false;
}

如果isSomething()在第一次迭代中返回true ,那么使用if语句的方法当然更快。 但是,平均速度是否更快?分支速度是否会变慢? 另外,如果循环速度更快,情况会有所不同吗? 在这里我使用了for-each循环来简化操作,我相信这比使用计数器的数组遍历要慢。


这两段代码并不完全相同。

尽管你只需要多次调用item.isSomething() (与我的原始答案相反),但第一个版本仍然继续尝试迭代集合的其余部分。

想象一下Item.isSomething()的实现,它修改了找到该项目的集合(如果它返回true )。 此时,第一段代码会抛出一个ConcurrentModificationException假设它是一个“常规”集合 - 而第二段代码只会返回true

从根本上讲,第二块代码更有效率:它只是遍历列表中的所有内容,而不是通过所有内容来确定答案。 很可能不同的表现是无关紧要的 - 特别是如果收藏量很小 - 但这取决于上下文。

你发现更可读的是一个不同的问题 - 效率可能不会很大,尽管这取决于上下文。 就我个人而言,我发现第二个版本更具可读性,更高效,所以我总是使用它。 (好吧,我会在if语句的主体周围添加大括号,但仅此而已。)


你是否在循环中循环十亿次? 如果不是,那么差别可能无法衡量。

你可以看看生成的字节码,看看到底发生了什么,但编译器,jit和vm本身可能会优化掉任何差异。


如果你想知道你的机器上哪个“更快”,那么运行它。

如果我们想知道哪些需要更多的指令来执行,那么我们可以看看字节码。

对于第一种方法,我们得到了这个(调用javap -c

Code:
   0: iconst_0      
   1: istore_1      
   2: getstatic     #2                  // Field listOfItems:Ljava/util/List;
   5: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
  10: astore_2      
  11: aload_2       
  12: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
  17: ifeq          50
  20: aload_2
  21: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
  26: checkcast     #6                  // class Item
  29: astore_3      
  30: iload_1       
  31: ifne          41
  34: aload_3       
  35: invokevirtual #7                  // Method Item.isSomething:()Z
  38: ifeq          45
  41: iconst_1      
  42: goto          46
  45: iconst_0      
  46: istore_1      
  47: goto          11
  50: iload_1       
  51: ireturn   

我们感兴趣的是循环的内部,即第29-46行(第11-26行是迭代器的东西)。 所以关于10条指令。

对于第二种方法,我们得到这个:

 Code:
       0: getstatic     #2                  // Field listOfItems:Ljava/util/List;
       3: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
       8: astore_1      
       9: aload_1       
      10: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      15: ifeq          40
      18: aload_1       
      19: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      24: checkcast     #6                  // class Item
      27: astore_2      
      28: aload_2       
      29: invokevirtual #7                  // Method Item.isSomething:()Z
      32: ifeq          37
      35: iconst_1      
      36: ireturn       
      37: goto          9
      40: iconst_0      
      41: ireturn       

感兴趣的线是27-37。 所以7条指令。

从数字的角度来看,第二种方法出现在最前面(注意,我们假设所有堆栈操作都需要相同的时间来执行)。

链接地址: http://www.djcxy.com/p/74691.html

上一篇: Is it more efficient to use a flag or an if clause?

下一篇: go build doesn't find my C standard library when compiling cgo package