【问题标题】:which of these is the most efficient in java? [duplicate]其中哪一个在 java 中是最有效的? [复制]
【发布时间】:2012-05-08 02:50:45
【问题描述】:

可能重复:
Java: If vs. Switch

对于在编程中观察到的所有条件语句,这些块中哪个是最优选的:

  1. 三元运算符
  2. else-if 块
  3. 开关块

提前致谢!

【问题讨论】:

  • 你为什么不对其进行基准测试并找出答案?
  • 你有性能问题吗?
  • 过早的优化,因为其中大多数可能会产生相同的字节码!
  • 之前在stackoverflow检查中被问到this
  • 这不是作业问题,否则我会将其标记为作业。谢谢@ChristopheD

标签: java performance conditional-statements


【解决方案1】:

当然,您可以用不同的方式进行比较。

我是这样做的:

普通方块:

int a = 42;
int k = 17;

如果:

if (a == 42) 
    k+=4;
else    k+=5;

案例:

switch (a) {
    case 42: k+=4; break;
    default: k+=5; break;
}

三元:

k += (a == 42) ? 4 : 5; 

它们不会编译成相同的字节码:

l *Tern*.class
-rw-r--r-- 1 stefan stefan 704 2012-04-27 14:26 CaseIfTern.class
-rw-r--r-- 1 stefan stefan 691 2012-04-27 14:26 IfTernCase.class
-rw-r--r-- 1 stefan stefan 728 2012-04-27 14:26 TernIfCase.class

但是,当您有多个案例时,switch 的优势就会发挥作用 - 而不仅仅是 2 个。

如果和三元级联超过 2 个案例。

但它们在惯用语/语义上有所不同。三元运算符返回一些东西,但不返回 if 或 switch。

因此,您需要比较的内容还不是很清楚。

但我做了一个基准测试,结果如下:

0   if      tern    case 
1   3.103   0.244   0.118   
2   0.306   0.276   0.309   
3   0.382   0.329   0.328   
4   0.464   0.435   0.458   
5   5.045   1.519   1.248   
6   4.57    3.088   2.915   
7   4.036   2.977   3.015   
8   3.197   3.834   3.893   
9   4.631   4.523   5.488   
10  6.445   3.891   3.09    

这表明,它们确实没有太大区别,而且缓存效果在 500 万个案例中仍然会产生影响,即使在虚拟机升温之后也是如此。

在实际情况下,您很少有数百万次调用几乎没有任何反应。但是如果发生了什么事,if/case/ternary 的时间很快就会变得无关紧要。

这是我测试的代码:

public class CaseTernIf
{
    public static int aORbIf (int a) {
        if (a == 2) 
            return 4;
        else    return 5;
    }

    public static int aORbTern (int a) {
        return  (a == 2) ? 4 : 5;
    }

    public static int aORbCase (int a) {
        switch (a) {
            case 2:  return 4;
            default: return 5; 
        }
    }
}

这是测试代码(Scala):

object IfCaseTernBench extends Benchcoat [List[Int], Seq[Int]] {

  type I=List[Int]
  type O=Seq[Int]
  val name = "CaseTern"
  /** We return a List of random Ints numbers here. */
  def iGenerator (n: Int) : I = (for (x <- 1 to n) yield math.abs (random.nextInt (3))).toList
  def takePart (li: I, n: Int) : I = li.take (n) 

  /* Each algorithm is called by a mapping to a static method.  */
  def ifTest   (i: I) : O = i.map (CaseTernIf.aORbIf) 
  def caseTest (i: I) : O = i.map (CaseTernIf.aORbCase) 
  def ternTest (i: I) : O = i.map (CaseTernIf.aORbTern) 

  // Map of Test names -> methods to test
  val list2bench: List [(String, I => O)] = List (
       "if test"    -> ifTest _
     , "case test"  -> caseTest _
     , "tern test"  -> ternTest _
  )

  def test = { 
     list2bench.foreach (algo => println (algo._2))
  }
}

更新:

这里是BenchCoat source

【讨论】:

  • 所以所有关于它被编译成相同字节码的说法都不正确?
  • @AnuragRamdasan:我想是的。由于代码大小不同。但也许另一个实现精确比较的内容,或者不同的编译器,或者 HotSpotCompiler 最终对代码所做的事情会改变情况。
  • @Neil:是的,谢谢,我更新了表格。在进行了或多或少的外观代码更改之后,我进行了第二次运行,以确保结果不会发生显着变化。更新图表后,我忘了更新表格。现在完成了。
  • @Neil:是的,但这不应该发生。我手动更正了它,但我必须调查此错误的来源。
  • 我有一个简单的问题。您究竟如何进行基准测试?我从来没有做过,我想我一旦完成我的应用原型就会需要它。只是一个链接会很棒。我真的很感激!
【解决方案2】:

如果您使用的是现代编译器,则没有太大区别。编译器优化代码后,原生代码应该差不多了。

【讨论】:

    【解决方案3】:

    三元运算符是最有效的,因为它不需要在 else-if 块需要的程序集中使用“goto”。我认为 switch case 并不比 else-if 块更有效,假设你在 else-if 块中所做的只是将一个值与另一个值进行比较(因为基本上这就是 switch 最终所做的一切)。

    但是,您应该考虑另一个考虑因素:清晰度。更重要的是选择最有效的用法是编写清晰简洁的代码。为此,我建议使用 else-if 或 switch 块而不是三元运算符,因为您开始睁大眼睛寻找否则返回的值。

    【讨论】:

    • 他只在性能方面询问。所以这不能回答问题
    • 您是否通过查看三元组生成的字节码来检查这一点?
    • @JohnDoe,我回答了他的问题并添加了更多相关信息。
    • 检查 this thread 实际测试这个。
    • 在上述条件块排列器案例中不使用 goto 时,汇编中没有 goto
    【解决方案4】:

    三元运算符只是 if (something) { yay } else { boo } 的一种简写形式,执行起来更简单。三元运算符将扩展为 if else 构造,字节码没有区别。

    【讨论】:

    • 请不要传播三元运算符是 if 语句的简写的神话。
    【解决方案5】:

    我做了以下测试:

    public class IfElseSwichTernary {
    
        public static int aORbIf(int a) {
            int x = 0;
    
            if (a == 2) {
                x = 4;
            } else if (a == 3) {
                x = 5;
            } else if (a == 4) {
                x = 6;
            } else {
                x = 7;
            }           
            return x;
        }
    
        public static int aORbTern(int a) {
            int x = 0;
    
            x = (a == 2) ? 4 : ((a == 3) ? 5 : ((a == 4) ? 6 : 7));         
            return x;
        }
    
        public static int aORbCase(int a) {
            int x = 0;
    
            switch (a) {
            case 2:
                x = 4;
                break;
            case 3:
                x = 5;
                break;
            case 4:
                x = 6;
                break;
            default:
                x = 7;
            }           
            return x;
        }
    }
    

    我用java反编译器反编译得到如下代码:

    公共类 IfElseSwichTernary {

    public static int aORbIf(int a) {
        int x = 0;
    
        if (a == 2) {
            x = 4;
        } else if (a == 3) {
            x = 5;
        } else if (a == 4) {
            x = 6;
        } else {
            x = 7;
        }           
        return x;
    }
    
    public static int aORbTern(int a) {
        int x = 0;
    
        x = (a == 2) ? 4 : ((a == 3) ? 5 : ((a == 4) ? 6 : 7));         
        return x;
    }
    
    public static int aORbCase(int a) {
        int x = 0;
    
        switch (a) {
        case 2:
            x = 4;
            break;
        case 3:
            x = 5;
            break;
        case 4:
            x = 6;
            break;
        default:
            x = 7;
        }           
        return x;
    }
    

    }

    这意味着编译器不会改变任何东西(我不知道JVM在转换它并运行指令时会不会改变)

    如果它以相同的逻辑表示,当我们谈论两个以上的条件时,Switch 更符合性能。

    【讨论】:

    • 您的 switch/case 缺少 break; 语句,并且失败了。
    【解决方案6】:

    这取决于 JVM 的实现以及版本,一般来说,你不能说语句是否最快

    例如生成的字节码也可以对所有语句都相同。

    【讨论】:

      猜你喜欢
      • 2012-08-23
      • 1970-01-01
      • 2012-11-27
      • 2013-02-03
      • 1970-01-01
      • 2010-10-08
      • 1970-01-01
      • 2013-01-21
      • 1970-01-01
      相关资源
      最近更新 更多