使用字符串选项优化if-else / switch-case

时间:2009-10-08 06:32:38

标签: java

这段代码会带来什么修改?在最后几行中,我应该使用更多 if-else 结构,而不是“ if-if-if”

if (action.equals("opt1"))
{
    //something
}
else
{
    if (action.equals("opt2"))
    {
        //something
    }
    else
    {
        if ((action.equals("opt3")) || (action.equals("opt4")))
        {
            //something
        }
        if (action.equals("opt5"))
        {
            //something
        }
        if (action.equals("opt6"))
        {
            //something
        }
    }
}

后来编辑:这是Java。我认为switch-case结构不适用于Strings。

后来编辑2:

  

一个开关与字节一起工作,简短,   char和int原始数据类型。它   也适用于枚举类型   (在类和继承中讨论)   还有一些“包装”的特殊课程   某些原始类型:角色,   字节,短整数和整数(讨论   在简单数据对象中。)

13 个答案:

答案 0 :(得分:10)

即使您不使用switch语句,是的,如果要避免无用的比较,请使用else:如果第一个 if ,则不希望在此处评估所有其他ifs因为他们总是假的。此外,您不需要缩进每个,如果使最后一个块如此缩进,以至于在没有滚动的情况下无法看到它,以下代码是完全可读的:

if (action.equals("opt1")) {
}
else if (action.equals("opt2")) {
}
else if (action.equals("opt3")) {
}
else {
}

答案 1 :(得分:5)

使用字符串作为键类型的字典,并将*作为值类型委托。 - 从使用字符串中检索方法将需要O(1 + load)。

在类的构造函数中填充字典。

  • Java不支持委托,因此解决方法可能需要定义一些内部类 - 每种情况一个,并传递内部类的实例而不是方法作为值。

答案 2 :(得分:4)

假设您的语言支持切换字符串,请使用switch语句。

switch(action)
{
   case "opt6":
      //
      break;
   case "opt7":
      //
   ...
   ...
   ...
}

答案 3 :(得分:4)

在Java中有很多方法可以做到这一点,但这里有一个很好的方法。

enum Option {
    opt1, opt2, opt3, opt4, opt5, opt6
}

...

switch (Option.valueOf(s)) {
case opt1:
    // do opt1
    break;
case opt2:
    // do opt2
    break;
case opt3: case opt4:
    // do opt3 or opt4
    break;
...
}

请注意,valueOf(String)如果参数将抛出IllegalArgumentException 不是枚举成员之一的名称。在引擎盖下,valueOf的实现使用静态hashmap将其String参数映射到枚举值。

答案 4 :(得分:2)

您可以使用开关。

switch (action)
{
 case "opt3":
 case "opt4":
 doSomething;
 break;
 case "opt5":
 doSomething;
 break;
 default:
 doSomeWork;
 break;
}

答案 5 :(得分:1)

这取决于您的语言,但它看起来像C一样,所以您可以尝试使用switch语句:

switch(action)
{
case "opt1":
    // something
    break;

case "opt2":
    // something
    break;

case "opt3":
case "opt4":
    // something
    break;

case "opt5":
    // something
    break;

case "opt6":
    // something
    break;
}

但是,有时switch语句不能提供足够的清晰度或灵活性(正如Victor在下面提到的那样,在某些语言中不适用于字符串)。大多数编程语言都会用“else if”来表示,而不是写

if (condition1)
{
    ...
}
else
{
    if (condition2)
    {
        ...
    }
    else
    {
        if (condition3)
        {
            ...
        }
        else
        {
            // This can get very indented very fast
        }
    }
}

...有一堆缩进,你可以写这样的东西:

if (condition1)
{
    ...
}
else if (condition2)
{
    ...
}
else if (condition3)
{
    ...
}
else
{
    ...
}

在C / C ++中,我相信C#,它是else if。在Python中,它是elif

答案 6 :(得分:1)

如果您指定语言可能会有所帮助......因为它看起来像C ++,您可以使用switch。

switch (action) {
   case "opt1":
      // something
      break;
   case "opt2":
      // something
      break;
   ...
}

如果您想使用if语句,我认为如果您使用“else if”而不使用花括号,您可以稍微提高可读性和性能,如:

if (action.equals("opt1")) {
    //something
} else if (action.equals("opt2")) {
    //something
} else if ((action.equals("opt3")) || (action.equals("opt4"))) {
    //something
} else if (action.equals("opt5")) {
    //something
} else if (action.equals("opt6")) {
    //something
}

我认为有些编译器可以比else if更好地优化else { if。无论如何,我希望我能帮忙!

答案 7 :(得分:1)

我只是将其清理为一系列if / else语句:

if(action.equals("opt1"))
{
    // something
}
else if (action.equals("opt2"))
{
    // something
}
else if (action.equals("opt3"))
{
    // something
}
etc...

答案 8 :(得分:0)

建议使用switch语句的答案是要走的路。切换语句比现在的ifif...else语句更容易阅读。

简单的比较很快,//something代码不会针对所有情况执行,因此您可以跳过“优化”并选择“可维护性”。

当然,假设action.equals()方法像==那样做了一些微不足道的事情。如果action.equals()价格昂贵,那么您还有其他问题。

答案 9 :(得分:0)

实际上这取决于分支分析。如果99%的决定是“opt1”,那么这段代码就已经相当不错了。如果99%的决定都是“opt6”,那么这段代码就是丑陋的。

如果您经常“opt6”并且很少“opt1”在第一次比较中加入“opt6”,并根据执行数据流中字符串的频率对以下比较进行排序。

如果您有很多选项并且所有选项都具有相同的频率,您可以对选项进行排序并将它们拆分为二进制树的形式,如下所示:

if (action < "opt20")
{
   if( action < "opt10" )
   {
     if( action  ==  "opt4" ) {...}
     else if( action  ==  "opt2" ) {...}
     else if( action  ==  "opt1" ) {...}
     else if( action  ==  "opt8" ) {...}
   }
}
else
{
    if( action < "opt30 )
    {

    }
    else
    {
      if( action  ==  "opt38" ) {...}
      else if( action  ==  "opt32" ) {...}
    }
}

在此示例中,范围拆分将“opt38”和“opt4”所需的比较减少到3.因此,您可以在每个分支中获得log2(n)+1比较。这对于选项的相同频率是最佳的。

不要二进制吐出到最后,最后使用4-10“正常”否则,如果按选项的频率排序的构造。二叉树中的最后两个或三个级别不需要太多进展。

<强>摘要

至少对这种比较有两种优化。

  1. 二元决策树
  2. 由于选项的频率而订购
  3. 二进制决策树由编译器用于大型switch-case结构。但是编译器对选项的频率一无所知。因此,如果一个或两个选项比其他选项更频繁,则根据频率的排序可以对开关盒的使用具有性能益处。在这种情况下,这是一种解决方法:

    if (action == "opt5") // Processing a frequent (99%) option first
    {
    }
    else // Processing less frequent options (>1%) second
    {
        switch( action )
        {
        case "opt1": ...
        case "opt2": ...
        }
    }
    

    警告

    在完成分析之前不要优化代码,这是非常必要的。最好使用switch-case或者 - 如果是直接的,你的代码保持干净和可读。如果您已经优化了代码,请在代码中添加一些好的注释,这样每个人都可以理解这种丑陋的代码和平。一年之后,您将不会知道分析数据,一些评论将非常有用。

答案 10 :(得分:0)

这样的程序切换通常由多态性更好地处理 - 而不是由字符串表示的动作,表示具有可以专门化的'某事'方法的对象的动作。如果您发现需要将字符串映射到该选项,请使用Map<String,Option>

如果你想坚持程序代码,真实代码中的选项都是“optX”:

if ( action.startsWith("opt") && action.length() == 4 ) {
    switch ( action.charAt(3) ) {
        case '1':  something; break;
        case '2':  something; break;
        case '3':  something; break;
        ...
    }
}

在类似解析器(破坏字符串是问题域的一部分)之类的东西中会很好,并且应该很快,但不具有内聚性(对象action与行为之间的连接是基于其表示的部分,而不是对象的任何内在因素)。

答案 11 :(得分:0)

请注意,在switch语句的情况下使用字符串是将在下一版Java中添加的新功能之一。

请参阅Project Coin: Proposal for Strings in switch

答案 12 :(得分:0)

如果您发现本机java开关构造过于局限,请查看允许通过将它们与某些hamcrest匹配器进行匹配来声明性地切换任何对象的lambdaj Switcher