与条件相比,速度



我有一个想法,我会使用条件运算符将我的一些if块变成单行。但是,我想知道是否会有速度差异。我运行了以下测试:

static long startTime;
static long elapsedTime;
static String s;
    
public static void main(String[] args) {
    startTime = System.nanoTime();
    s = "";
    for (int i= 0; i < 1000000000; i++) {
        if (s.equals("")) {
            s = "";
        }
    }
    
    elapsedTime = System.nanoTime() - startTime;
    
    System.out.println("Type 1 took this long: " + elapsedTime + " ns");
    
    startTime = System.nanoTime();
    s = "";
    for (int i= 0; i < 1000000000; i++) {
        s = (s.equals("") ? "" : s);
    }
    
    elapsedTime = System.nanoTime() - startTime;
    
    System.out.println("Type 2 took this long: " + elapsedTime + " ns");
}

这是我的结果:

类型 1 花了这么长时间:3293937157 ns

类型 2 花了这么长时间:2856769127 ns

我在这里做错了什么吗?

假设s.equals("")一定是正确的,这是使代码更快的可行方法吗?

, is this a viable way to make your code faster?

如果您的String s;是非静态字段,您甚至可以使其更快。静态场比非静态场慢,当你referencing十亿次时

public static void main(String[] args) {
    startTime = System.nanoTime();
    String s = "";
    .
    .
}

编辑:

为什么更快??

这是由于字符串对静态字段的引用。

你可以在它的字节码中看到它

    0: ldc           #23                 // String
       2: putstatic     #25                 // Field s:Ljava/lang/String;
       5: iconst_0
       6: istore_1
       7: goto          22
      10: getstatic     #25                 // Field s:Ljava/lang/String;
      13: ldc           #23                 // String
      15: invokevirtual #27                 // Method java/lang/String.equals:(L
java/lang/Object;)Z
      18: pop
      19: iinc          1, 1
      22: iload_1
      23: ldc           #33                 // int 1000000000
      25: if_icmplt     10
      28: return

如您所见getStaticputStatic将被调用十亿次,它的作用是调用静态字段的引用并使用 putStatic 放置字符串的引用

getStatic - 获取类的静态字段值,其中该字段由常量池索引中的字段引用标识(index1 <<8 + index2(

putStatic - 将静态字段设置为类中的值,其中字段由常量池中的字段引用索引标识(索引字节 1 <<8 + 索引字节 2(

查看那些导致程序缓慢的位移

此外,如果您使用的是global/member field它将创建相同的字节码,但相反,它将使用 getfieldputfield与静态的getStaticputStatic相同

现在让我们看看non static field字节码

      0: ldc           #21                 // String
       2: astore_1
       3: iconst_0
       4: istore_2
       5: goto          23
       8: aload_1
       9: ldc           #21                 // String
      11: invokevirtual #23                 // Method java/lang/String.equals:(L
java/lang/Object;)Z
      14: ifeq          20
      17: ldc           #21                 // String
      19: astore_1
      20: iinc          2, 1
      23: iload_2
      24: ldc           #29                 // int 1000000000
      26: if_icmplt     8
      29: return

如您所见,它仅使用 astore_1aload_1 来保存和加载非静态字段的引用,而无需额外操作。

这对我来说确实闻起来像是过早的优化。如果您仍然打算以这种方式对这两种实现进行微基准测试,我建议您改用isEmpty(),因为与equals()相比,底层代码更直接。我的意思是编译器/JVM将为您进行的任何优化都不太可能被equals()中发生的事情触发,并且更多地反映一个实现相对于另一个实现的任何微小好处,假设这真的很重要。

可读性应该是您决定是要使用if-else还是? :的更好规则。

其他答案具有相关的有用信息,但没有一个解决一种形式是否比第二种形式更有效的真正问题。

这种基准测试不能提供可靠的结果,因为它没有正确完成:对Java代码进行基准测试的一个重要"经验法则"是提供热身。在这种情况下,第一个循环为第二个循环提供预热。

本答案提供了微基准测试的其他说明以及一些有用的链接。

相关内容

  • 没有找到相关文章

最新更新