【问题标题】:How can I avoid repeated if-statement?如何避免重复的 if 语句?
【发布时间】:2011-03-26 02:48:16
【问题描述】:

我写了一个java应用程序来处理日志文件有数百万行 程序中有这样的伪代码

if(optionA is On)
  call object A's method

if(optionB is On)
  call object B's method

if(optionC is On)
  call object C's method
...

IF 中的选项是从配置文件中获取的配置值 这个伪代码在每个日志行中调用,所以调用了百万次

由于速度和简单性,我想删除这个多 IF。 看到这么多的IF让我很不愉快。 有没有一个很好的方法来解决这个烦人的 IF?

【问题讨论】:

  • 您是否担心 1) 方法的可扩展性(您不断添加 if 语句),2) 方法的美学(您不想阅读所有这些语句),3 )方法的性能(它太慢了),还是这些的某种组合?如果您更清楚为什么要减少ifs 的数量,我们或许可以提供更多帮助
  • 不懂java,但你不能使用接口/虚拟方法并为对象和选项使用列表。像for(i=0;i<objectlist.count();i++) if(option[i])objectlist[i].method();

标签: java optimization if-statement


【解决方案1】:

如果对象共享一个公共接口,您可以创建这样的方法:

private void callOptional(myInterface obj, boolean flag) {
  if (option) obj.method();
}

这样您就消除了 IF。但是您仍然有一长串通用代码。为了让它更干,我会将对象引用添加到存储选项的列表中,然后执行一个 for 循环:

for (OptionObjectPair ooPair : optionObjectList) {
  callOptional(ooPair.obj, ooPair.flag)
}

然后您甚至可以更改 callOptional 方法的接口以直接获取 OptionObjectPair。

【讨论】:

  • 呃,对每个没有选项的对象的对象调用都是徒劳的,正在优化? Java 好笑吗?
  • @stefan:是的,JVM 不会内联方法——不,别担心,我们只进行了 40 年的优化,而不是 30 年的优化:p
【解决方案2】:

if 语句的长序列并不总是是件坏事。但是,如果您想以正确的方式进行,则必须在数据结构中定义选项到其“处理程序”的映射,而不是在 if 语句中对其进行硬编码。

您可以定义一个单一方法接口并让ABC(在您的示例中)实现它:

public interface OptionHandler { // For lack of a better name...
    void handleOption(); // You could pass parameters here
}

然后您可以定义选项映射到它们的处理程序:

private final Map<Option, OptionHandler> optionHandlers = new HashMap<Option, OptionHandler>();

然后,您可以将 if 语句序列替换为以下内容:

for (Option option : options) {
    if (!option.isOn()) {
        // Skip off option
        continue;
    }
    OptionHandler handler = optionHandlers.get(option);
    if (handler != null) {
        handler.handleOption();
    }
}

【讨论】:

    【解决方案3】:

    这真的取决于你想要优化什么(见 templatetypedef 的评论)。如果你只是想减少代码占用,你可以这样做

    // let's assume you have an Option interface with isTrue() method
    // let's assume you have an Action interface with performAction() method
    
    Map<Option,Action> actions = new HashMap<Option,Action>();
    // initialize actions with instance of your objects so that you have:
    // optionA -> actionA
    // optionB -> actionB
    // etc.
    // this is done only once
    
    Option[] currentOptions;
    // read the current option values and put them in an array
    for (int i = 0; i < currentOptions.lengt; i++) {
        if (currentOptions[i].isTrue())
            actions.get(currentOptions[i]).performAction();
    }
    

    【讨论】:

      【解决方案4】:

      如果所有对象的方法都相同,则创建选项到对象的哈希表并根据选项调用方法。

      HashMap<Option,ActionObject> map ;
      for (Option option: map.keySet()) {
          if (optionIsTrue(option)) {  
              map.get(option).performAction() ;
          }
      }
      

      【讨论】:

      • 为什么是 hashmap 而不仅仅是数组/向量?
      • 这只解决了一半的问题:只有当Option 实例为真时,他才需要调用performAction()
      • @stefan,因为如果你使用一个数组,你将不得不保留两个数组,并根据索引从选项映射到对象。
      • @marcos,第二行可以放入for循环。我正在编辑我的答案以反映这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-11
      • 2019-05-02
      • 2022-01-09
      • 2020-09-19
      相关资源
      最近更新 更多