java 如何减少if语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16669753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 23:36:32  来源:igfitidea点击:

How to reduce if statements

javaif-statementswitch-statementfizzbuzz

提问by Calgar99

The program below functions as necessary but how do I reduce the amount of if statements. I have been told that if your function contains 2 or more if statements then your doing it wrong. Any suggestions? I've tried using switch statements but that hasn't worked because the case can't be a boolean.

下面的程序根据需要运行,但我如何减少 if 语句的数量。有人告诉我,如果您的函数包含 2 个或更多 if 语句,那么您做错了。有什么建议?我试过使用 switch 语句,但这没有用,因为 case 不能是布尔值。

for(int i = 1; i < 100; i++)
        {
        if(i % 10 == 3) 
        {
            System.out.println("Fizz" + "(" + i + ") 3%10");
        }

        if(i / 10 == 3)
        {
            System.out.println("Fizz" + "(" + i + ") 3/10");
        }


        if(i % 10 == 5) 
        {
            System.out.println("Buzz" + "(" + i + ") 5%10");
        }

        if(i / 10 == 5)
        {
            System.out.println("Fizz" + "(" + i + ") 5/10");
        }

        if(i / 10 == 7)
        {
            System.out.println("Fizz" + "(" + i + ") 7/10");
        }

        if(i%10 == 7)
        {
            System.out.println("Woof" + "(" + i + ") 7%10");
        }

        if(i % 3 == 0)
        {
            System.out.println("Fizz" + "(" + i + ") 3%==0");
        }

        if(i % 5 == 0)
        {
            System.out.println("Buzz" + "(" + i + ")5%==0");
        }

        if(i % 7 == 0)
        {
            System.out.println("Woof" + "(" + i + ")7%==0");    
        }

        if( (i % 7 !=0 ) && (i % 3 !=0 ) && (i % 5 !=0 )
                && (i % 10 !=3) && (i % 10 !=5 ) && (i%10 !=7 ) )
            System.out.println(i);
    }

回答by John B

How about creating a method for the cases:

如何为案例创建一个方法:

 public void printIfMod(int value, int mod){
       if (value % 10 == mod)
          System.out.println(...);
 }

 public void printIfDiv(int value, int div){
       if (value / 10 == div)
          System.out.println(...);
 }

Then instead of a bunch of ifyou have a set of calls the the two methods. You might even create a single method that calls both of the above.

然后,而不是一堆if你有一组调用这两个方法。您甚至可以创建一个调用上述两种方法的方法。

 public void printIf(int value, int div){
      printIfMod(value, div);
      printIfDiv(value, div);
 }

 for(int i = 1; i < 100; i++) {
      printIf(i, 3);
      printIf(i, 5);
      ....
 }

In the above code the number of ifsis less of an issue to me than the amount of repeated code.

在上面的代码中ifs,重复代码的数量对我来说不是问题。

回答by Sean Patrick Floyd

Here's a slight improvement using two switch statements

这是使用两个 switch 语句的轻微改进

switch(i / 10){
  case 3: // do something
    break;
  case 5: // do something else
    break;
  case 7: // do something else
    break;
}

switch(i % 10){
  case 3: // do something
    break;
  case 5: // do something else
    break;
  case 7: // do something else
    break;
}

Unfortunately you'll need one switch statement per divisor.

不幸的是,每个除数都需要一个 switch 语句。

Alternatively, you can embrace OOP and come up with an abstraction like this:

或者,您可以拥抱 OOP 并提出这样的抽象:

public abstract class Processor {
    private final int divisor;
    private final int result;
    private final boolean useDiv; // if true, use /, else use %

    public Processor(int divisor, int result, boolean useDiv) {
        this.divisor = divisor;
        this.result = result;
        this.useDiv = useDiv;
    }
    public final void process(int i){
        if (
             (useDiv && i / divisor == result)
             || (!useDiv && i % divisor == result)
           ){
                doProcess(i);
            }
    }

    protected abstract void doProcess(int i);
}

Sample usage:

示例用法:

public static void main(String[] args) {
    List<Processor> processors = new ArrayList<>();
    processors.add(new Processor(10, 3, false) {
        @Override
        protected void doProcess(int i) {
            System.out.println("Fizz" + "(" + i + ") 3%10");
        }
    });
    // add more processors here
    for(int i = 1; i < 100; i++){
        for (Processor processor : processors) {
            processor.process(i);
        }
    }

}

回答by mprivat

Generally speaking, it's true that code that has a lot of ifstatements looks suspicious. Suspicious doesn't necessarily mean wrong. If the problem statement has disjoint conditions to check for (i.e. you can't group them) then you have to do them independently like you're doing.

一般来说,确实有很多if语句的代码看起来很可疑。可疑并不一定意味着错误。如果问题陈述有不相交的条件需要检查(即你不能将它们分组),那么你必须像你正在做的那样独立地做它们。

In your case, you're having to check for divisibility without being able to infer one from the other (i.e. if x is divisible by 7, it doesn't mean it's also divisible by 5, etc...). All the numbers you are using have been purposely chosen prime so this is why you're getting into this.

在您的情况下,您必须检查可分性而不能从另一个推断出一个(即,如果 x 可以被 7 整除,这并不意味着它也可以被 5 整除,等等......)。您使用的所有数字都被故意选择为素数,所以这就是您要参与其中的原因。

If for example they had said, check for divisibility by 2, 3, and 6. Then you could first check for 6 because then you could also imply divisibility by 2 and 3. Or vice-versa, check by 2 and 3 and imply that it's also divisible by 6. If all the numbers are prime, then you just can't imply. So you're code has to check for everything individually.

例如,如果他们说,检查可被 2、3 和 6 整除。然后您可以先检查 6,因为这样您也可以暗示可被 2 和 3 整除。反之亦然,检查 2 和 3 并暗示它也可以被 6 整除。如果所有数字都是质数,那么你就不能暗示。因此,您的代码必须单独检查所有内容。

One positive side effect is it makes your intent easy to read in your code (because it's all explicit).

一个积极的副作用是它使您的意图在您的代码中易于阅读(因为它都是明确的)。

My two cents on this...

我的两分钱...

回答by OldCurmudgeon

Enums are a good fit here. They allow you to encapsulate the functionality in one location rather than spreading it throughout your flow control.

枚举非常适合这里。它们允许您将功能封装在一个位置,而不是将其分散到整个流程控制中。

public class Test {
  public enum FizzBuzz {
    Fizz {
      @Override
      String doIt(int n) {
        return (n % 10) == 3 ? "3%10"
                : (n / 10) == 3 ? "3/10"
                : (n / 10) == 5 ? "5/10"
                : (n / 10) == 7 ? "7/10"
                : (n % 3) == 0 ? "3%==0"
                : null;
      }

    },
    Buzz {
      @Override
      String doIt(int n) {
        return (n % 10) == 5 ? "5%10"
                : (n % 5) == 0 ? "5%==0"
                : (n / 10) == 3 ? "3/10"
                : (n / 10) == 5 ? "5/10"
                : (n / 10) == 7 ? "7/10"
                : null;
      }

    },
    Woof {
      @Override
      String doIt(int n) {
        return (n % 10) == 7 ? "7%10"
                : (n % 7) == 0 ? "7%==0"
                : null;
      }

    };

    // Returns a String if this one is appropriate for this n.
    abstract String doIt(int n);

  }

  public void test() {
    // Duplicates the posters output.
    for (int i = 1; i < 100; i++) {
      boolean doneIt = false;
      for (FizzBuzz fb : FizzBuzz.values()) {
        String s = fb.doIt(i);
        if (s != null) {
          System.out.println(fb + "(" + i + ") " + s);
          doneIt = true;
        }
      }
      if (!doneIt) {
        System.out.println(i);
      }
    }
    // Implements the game.
    for (int i = 1; i < 100; i++) {
      boolean doneIt = false;
      for (FizzBuzz fb : FizzBuzz.values()) {
        String s = fb.doIt(i);
        if (s != null) {
          if ( doneIt ) {
            System.out.print("-");
          }
          System.out.print(fb);
          doneIt = true;
        }
      }
      if (!doneIt) {
        System.out.print(i);
      }
      System.out.println();
    }
  }

  public static void main(String args[]) {
    try {
      new Test().test();
    } catch (Throwable t) {
      t.printStackTrace(System.err);
    }
  }

}

回答by Matt Taylor

I had started to write an answer involving code, but many, many people beat me to it. The one thing I would say which hasn't been mentioned yet is that this particular code metric you're referring to is called cyclomatic complexityand isn't a horrendously bad thing.

我已经开始写一个涉及代码的答案,但是很多很多人打败了我。我要说的一件事还没有提到,你所指的这个特定的代码度量被称为圈复杂度,并不是一件非常糟糕的事情。

In short it refers to the number of different paths that a method could take when it's executed, and while it's quite high in the code snipped that you posted, and there are lots of good tips/solutions to reducing it that have been suggested, personally I would argue that even in it's current form, the code is very readable - which is a bonus. It can be reduced a fair amount and still be readable, but my point is that metrics like that aren't everything, and sometimes it can be simpler to have lots of ifstatements because it's more readable - and readability reduces the likelihood of making mistakes, and makes debugging much easier

简而言之,它指的是一个方法在执行时可以采用的不同路径的数量,虽然它在您发布的代码片段中相当高,并且有很多很好的技巧/解决方案可以减少它的建议,个人建议我会争辩说,即使是当前的形式,代码也非常易读——这是一个额外的好处。它可以减少相当数量并且仍然可读,但我的观点是,像这样的指标并不是一切,有时拥有大量if语句会更简单,因为它更具可读性 - 可读性降低了犯错误的可能性,并使调试更容易

Oh, and I would replace this last section:

哦,我会替换最后一部分:

if( (i % 7 !=0 ) && (i % 3 !=0 ) && (i % 5 !=0 )
            && (i % 10 !=3) && (i % 10 !=5 ) && (i%10 !=7 ) )
        System.out.println(i);

By using a boolean flag such as replaced = truewhenever any of the replacement statements are called, then the above statement collapses to:

通过使用布尔标志,例如replaced = true每当调用任何替换语句时,上述语句将折叠为:

if (!replaced)
      System.out.println(i);

回答by John

I would argue, that you're asking the wrong question. The question I think you should ask is: "How can I rewrite this code so that it is more easily understood by a human?"

我会争辩说,你问错了问题。我认为你应该问的问题是:“我怎样才能重写这段代码,让它更容易被人类理解?”

The creed "eliminate if statements" is a general idea to accomplish this, but it depends heavily on the context.

信条“消除 if 语句”是实现这一目标的一般想法,但它在很大程度上取决于上下文。

The sad fact is that many of the answers obfuscate this very simple algorithm in the guise of "making it simpler." Never introduce an object to eliminate a couple of if statements. In my work, most code is maintained by people that understand far less about the architecture, math and code than the original author, so to introduce additional constructs and complexity to reduce the code from 50 physical lines to 30 physical lines, but makes it 4 times more difficult to understand is not a win.

可悲的事实是,许多答案以“使其更简单”为幌子混淆了这个非常简单的算法。永远不要引入一个对象来消除几个 if 语句。在我的工作中,大多数代码是由对架构、数学和代码了解远不及原作者的人维护的,因此引入额外的结构和复杂性以将代码从 50 行物理行减少到 30 行物理行,但使其成为 4次更难理解不是赢。

回答by Bohemian

Your code is repetitive. Refactor it using loops for your:

你的代码是重复的。使用循环重构它:

for (int i = 1; i < 100; i++) {
    boolean found = false; // used to avoid the lengthy test for "nothing found"
    for (int j = 3; j <= 7; j += 2) { // loop 3, 5, 7
        if (i % 10 == j) {
            System.out.println("Fizz" + "(" + i + ") "+j+"%10");
            found = true;
        }

        if (i / 10 == j) {
            System.out.println("Fizz" + "(" + i + ") "+j+"/10");
            found = true;
        }

        if (i % j == 0) {
           System.out.println("Fizz" + "(" + i + ") "+j+"%==0");
           found = true;
        }
    }

    if (!found) {
        System.out.println(i);
    }
}

回答by DeadlyJesus

You can create multiple switch:

您可以创建多个开关:

switch (i/10) {
     case 3:
        System.out.println("Fizz" + "(" + i + ") 3/10");
        break;

    case 5:
        System.out.println("Fizz" + "(" + i + ") 5/10");
        break;

    case 7:
        System.out.println("Fizz" + "(" + i + ") 7/10");
        break;
    default:
        break;
}

switch (i%10) {
    case 3: 
        System.out.println("Fizz" + "(" + i + ") 3%10");
        break;
    case 5:
        System.out.println("Buzz" + "(" + i + ") 5%10");
        break;
    case 7:
        System.out.println("Woof" + "(" + i + ") 7%10");
        break;
    default:
        break;
}

The other case still have to use if statement.
Oracle added switch statement that used Stringin Java 7. Maybe boolean switch statement will come later.

另一种情况还是要使用if语句。
Oracle 添加String了 Java 7中使用的 switch 语句。也许以后会出现布尔 switch 语句。

回答by AmitG

public class Test
{

    public static void main(String[] args)
    {

        final int THREE = 3;
        final int FIVE = 5;
        final int SEVEN=7;
        final int ZERO = 0;

        for (int i = 1; i < 100; i++)
        {
            modOperation("Fizz", i, THREE);

            divideOperation("Fizz", i, THREE);


            modOperation("Fizz", i, FIVE);

            divideOperation("Buzz", i, FIVE);



            modOperation("Woof", i, SEVEN);

            divideOperation("Fizz", i, SEVEN);


            modOperation("Fizz", i, ZERO);

            divideOperation("Fizz", i, ZERO);
        }

    }

    private static void divideOperation(String sound, int i, int j)
    {
        if (i / 10 == j) // you can add/expand one more parameter for 10 and later on 3 in this example.
        {
            System.out.println(sound + "(" + i + ") "+j+"/10");
        }
    }

    private static void modOperation(String sound, int i, int j)
    {
        if (i % 10 == j)
        {
            System.out.println(sound + "(" + i + ") "+j+"%10");
        }
    }
}

So now you have less if

所以现在你少了 if