如何删除大的if-else-if链

时间:2011-09-08 14:43:38

标签: java string optimization if-statement

  

可能重复:
  Long list of if statements in Java

我的任务是处理一些代码,并且有一个巨大的if-else-if链(100+ else-ifs)检查字符串。

更新此代码有哪些好方法可以将if-else-if链缩小到更易于管理的内容。

链看起来像这样:

if(name.equals("abc")){
    do something
} else if(name.equals("xyz")){
    do something different
} else if(name.equals("mno")){
    do something different
} ......
.....
else{ 
   error
}

6 个答案:

答案 0 :(得分:18)

您可以将每个分支中的代码提取到单独的方法,然后将这些方法转换为公共基本接口的实现(让我们称之为Handler)。之后,您可以填写Map<String, Handler>,只需查找并执行给定字符串的正确处理程序。

不幸的是,为接口实现100多个子类需要相当多的样板代码,但目前在Java中没有更简单的方法来实现这一点。将案例实现为Enum的元素可能会有所帮助 - here is an example。理想的解决方案是使用闭包/ lambda,但是我们必须等到Java 8 ...

答案 1 :(得分:8)

一些选项/想法:

  • 保持原样 - 它没有从根本上打破,并且相当清晰且易于维护
  • 使用switch语句(如果您使用的是Java 7) - 不确定这是否会让您获益更多
  • 创建String的HashMap到FunctionObjects ,其中函数对象实现所需的行为作为方法。然后您的调用代码就是:hashMap.get(name).doSomething();
  • 通过对字符串进行子分组将其分解为函数调用的层次结构。你可以依次取每个字母来做到这一点,所以一个分支处理所有以'a'等开头的名字。
  • 重构,以便您不会将名称作为String传递,而是传递命名对象。然后你可以namedObject.doSomething()

答案 2 :(得分:8)

使用Enums,您可以为每个实例设置一个方法。

public enum ActionEnum {
   ABC {
      @Override
      void doSomething() {
          System.out.println("Doing something for ABC");    
      }

   },
   XYZ {
      @Override
      void doSomething() {
         System.out.println("Doing something for XYZ"); 
      }
   };

   abstract void doSomething();
}

public class MyActionClass {

    public void myMethod(String name) {
        ActionEnum.valueOf("ABC").doSomething();
    }

}

它仍然有点混乱(有100多个条目的大枚举,即使它只是调度),但可以避免HashMap初始化代码(在我看来,100 + puts也很混乱)。

另一种选择(出于文档目的)将是反思:

public interface Action {
    void doSomething();
}

public class ABCAction implements Action {
    @Override
    public void doSomething() {
        System.out.println("Doing something for ABC");      
    }
}

public class MyActionClass {

    void doSomethingWithReflection(String name) {
        try {
            Class<? extends Action> actionClass = Class.
                forName("actpck."+ name + "Action").asSubclass(Action.class);
            Action a = actionClass.newInstance();
            a.doSomething();
        } catch (Exception e) {
            // TODO Catch exceptions individually and do something useful. 
            e.printStackTrace();
        }
    }
}

每种方法都有权衡:

  • HashMap = Fast + Kinda messy(“设置”代码有数百个put)
  • Enum = Fast + Kinda messy 2(巨大文件)。
  • 反射=较慢+运行时容易出错,但提供干净的分离而无需使用笨重的大HashMap。

答案 3 :(得分:7)

就像Matt Ball在评论中所说,你可以使用命令模式。定义Runnable类的集合:

Runnable task1 = new Runnable() {
    public void run() { /* do something */ }
};
Runnable task2 = // etc.

然后你可以使用钥匙上的地图来运行:

Map<String,Runnable> taskMap = new HashMap<String,Runnable>();
taskMap.put("abc", task1);
taskMap.put("xyz", task2);
// etc.

最后,将if-else链替换为:

Runnable task = taskMap.get(name);
if (task != null) {
    task.run();
} else {
    // default else action from your original chain
}

答案 4 :(得分:2)

您可以使用switch语句,但已在Java SE 7

中实现了带有String案例的Switch语句

最佳解决方案是使用command pattern

答案 5 :(得分:0)

这是一个受欢迎的Arrow Anti-Pattern,杰夫在他的帖子here中讨论了一些处理这个问题的方法。