Java中if语句的替代方案是什么?

7

我很想看看除了常规的if语句之外的其他选择,例如

if(x)
     do a;
if(y)
     do b;
if(z)
    do c;

如您所见,所有的if条件语句都是独立的,没有else条件。请注意,X、Y、Z是完全独立的条件,因此switch语句不适用。


4
尽管好奇心可能有些幽默,但如果条件是转换不适用,为什么我要寻求if的替代方案呢?好像Java已经足够臃肿了... - ty812
你要么在做一些愚蠢的事情(if语句很好用!),要么就需要提供更多信息。我可以想象一种情况,使用消息传递模式或其他有趣的方法可以处理这样的代码(前提是你的情况不像你解释的那么简单)。 - twolfe18
你期望这个替代方案提供什么,而原有的代码无法提供?(更少的字符,更好的可读性?) - Zed
嗯,我只是在探索,我知道“if”语句很优雅且易于阅读,但额外的知识从来没有伤害过。 - Hellnar
3
有些知识具有价值,而有些则是晦涩难懂的代码高尔夫垃圾。 - S.Lott
2
足够大量的 if 语句是有害的。 - Alex R
11个回答

32

一个真正面向对象的方法是为 "Rule" 定义一个接口(包括 condition() 和 action() 方法),创建 3 个实现类,将它们放入集合中,然后像这样通用地迭代它们:

List<Rule> rules = .... ; //在此处初始化你的 3 条规则
for(Rule r : rules) {
  if(r.condition()) {
    r.action();
  }
}

如果你有 300 条规则/条件,那么这种方法就更为合理。

在 Java8 中,如果规则具有 CPU 密集性,则可以使用以下方法:

rules.parallelStream().filter(Rule::condition).forEach(Rule::action);

你可以使用 Map 来实现 O(1) 的时间复杂度,而不是 O(n)。 - Dave Jarvis
这里不能使用Map,因为每个规则实现的条件都是独特的。Map需要一个实际的键,而不是嵌在可调用方法中的一些代码。 - Alex R

9
简短的回答是肯定的。
有些情况下,您可以完全避免使用 if 进行条件评估和分支。它们在某些情况下是合适的。
  1. Polymorphism, when behavior is dependent on the initial values
  2. Referrenced Assignment, when you know the possible initial values and they have 1 to 1 correlation with the return values. Lists are better than arrays for this, but...

    // Example:  
    if (a==1) { b=2;  }  
    if (a==2) { b=17; }  
    
    // Becomes  
    int fx(2);  // our array of answers  
    fx[0] = 2;   
    fx[1] = 17;  
    b = fx[ a - 1 ];
    
  3. Referrenced Branching, when you know the possible initial values and they have 1 to 1 correlation with the function/branch to use. (example not Java)

    // Example:
    if (a==1) { doSomething1();  }  
    if (a==2) { doSomething2(); }  
    
    // Becomes
    function * fx(2);  // our array or better still, list of functions  
    fx[0] = &doSomething1;   
    fx[1] = &doSomething2;  
    `fx[ a - 1 ](); `
    
  4. Direct boolean assignment.

    We hate:

    if (thisCondition == true) {  
      b = true;  
    } else {  
      b = false;  
    }
    

    Should be:

    b = thisCondition;


6
在Java中,替代if-else的方法有switch语句和条件三目运算符?:),但它们都不能完全满足您的需求(仅处理没有elseif)。在我看来,您发布的代码是最好的方法。请注意保留HTML标记。

三元运算符中的多个条件:https://dev59.com/rGcs5IYBdhLWcg3w0HSz - Vacca

4

使用多态性。

interface SomethingDoer {
    public void doSomething();
}

class ADoer implements SomethingDoer { ... }
class BDoer implements SomethingDoer { ... }
class CDoer implements SomethingDoer { ... }

public class Main {
     public static void main (String[] args) {
          SomethingDoer doer = new SomethingDoerFactory(args).getDoer();
          doer.doSomething();
     }
}

if语句并未完全被消除,而是移动到了SomethingDoerFactory中。这种解决方案并不适用于所有情况,但在某些情况下,它是多个if的很好替代方案。
以下是一段有关此话题的精彩演讲:
http://misko.hevery.com/2008/12/08/clean-code-talks-inheritance-polymorphism-testing/

1
你为什么要点踩呢?有什么不同的看法吗?或者是因为它不够好而不值得一提? - artemb
3
只有当我的条件语句已经基于 "类型" 时,我才会考虑使用多态解决方案。 我不会创建整个类层次结构来替换 if(x) do a; - Bill the Lizard
2
如果有意义的话,可以查看Google技术讲座中的http://www.youtube.com/watch?v=4F72VULWFvc(《清晰代码讲解》——继承、多态和测试)。我认为这个踩票是错误的。 - Andreas Petersson
1
直接引用Misko的Slides:“有时候<code>if</code>只是一个<code>if</code>”。除非您在许多地方重复使用这些<code>if</code>语句,否则这将使事情变得不必要地复杂。此外,您的解决方案是不完整的。如果条件x和y都成立怎么办?您错过了AAndBDoer、AAndCDoer、BAndCDoer、AAndBAndCDoer;这些都已被原始代码很好地覆盖。 - Zac Thompson
显然,这取决于“做a”究竟意味着什么。多态可能是一个很好的解决方案,但这个例子太过通用,无法为所有情况提供单一的解决方案。AAndBDoer等问题通常通过使用装饰器/组合模式来解决,以实现多态类型的解决方案。 - Eek

3

这是最简单、易读且有效的解决方案。如果有其他有效的替代方案,我会感到惊讶。

编辑

您可以尝试多次应用“提取方法”:

doAIfX();
doBIfY();
doCifZ();

方法的定义方式如下:

void doAIfX() {
    if (!X) {
        return;
    }

    // do 'a'
}

我在设备的固件中完成这个任务,该设备可以启用或禁用许多不同的选项。我宁愿让我的main()函数调用像doFooIfEnabled()这样的东西,而不是用大量的ifs和#ifdefs来使其混乱不堪。 - Jeanne Pindar
1
像任何一种模式一样,有时候应该使用它,有时候则不应该。 - bdonlan

2

可以像这样做,根据条件实现枚举并调用覆盖方法。

public enum Rule{
            a(){
            @Override
            public void do(){
            // do something.
            }
            },
            b(){
            @Override
            public void do(){
            // do something.
            }
            },
            c(){
            @Override
            public void do(){
            // do something.
            }


            public abstract void do();

            }
        }




     public class Test{
            public static void main(String[] args){
                Rule r = Rule.valueOf("a");
                r.do();
            }
        }

0

如何使用以下代码...

myAnimator(thing, pos, speed | computeSpeed());

如果speed === undefined,则会计算速度...我想是这样的。


0

这真的取决于 x、y、z 和 a、b、c 是什么。有时候 if 语句更合适,有时候多态更合适。


0

你需要在某个地方使用这些 if 语句。

它们可以重构到其他方法中,以保持当前方法的清晰度,正如其他人所建议的那样。如果你需要在多个地方重复使用这个集合的 if 语句,可能可以使用装饰器模式


0

这似乎是使用闭包的完美案例。但是为此,您需要使用Groovy或类似的东西。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接