如何减少if语句

时间:2013-05-21 12:13:59

标签: java if-statement switch-statement fizzbuzz

下面的程序可以根据需要运行,但如何减少if语句的数量。有人告诉我,如果你的函数包含2个或更多if语句,那么你做错了。有什么建议?我尝试过使用switch语句,但由于案例不能是布尔值,因此无效。

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);
    }

9 个答案:

答案 0 :(得分:49)

如何为案例创建方法:

 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(...);
 }

然后,您可以使用两种方法调用一组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); .... } 。您甚至可以创建一个调用上述两种方法的方法。

ifs

在上面的代码中,{{1}}的数量对我来说不是重复代码的数量。

答案 1 :(得分:26)

使用两个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;
}

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

或者,您可以接受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);
}

样本用法:

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);
        }
    }

}

答案 2 :(得分:12)

一般来说,拥有大量if语句的代码看起来很可疑。可疑并不一定意味着错误。如果问题陈述有不相同的条件要检查(即你不能对它们进行分组),那么你必须像你一样独立完成它们。

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

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

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

我的两分钱......

答案 3 :(得分:8)

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

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);
    }
  }

}

答案 4 :(得分:7)

我已经开始写一个涉及代码的答案,但是很多人都打败了我。我要说的一件事还没有提到,你所指的这个特定的代码指标叫做cyclomatic complexity,并不是一个可怕的坏事。

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

哦,我会替换最后一节:

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

通过在调用任何替换语句时使用诸如replaced = true之类的布尔标志,上述语句将折叠为:

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

答案 5 :(得分:7)

我认为,你问的是错误的问题。我认为你应该问的问题是:“我怎样才能重写这段代码,以便人类更容易理解?”

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

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

答案 6 :(得分:5)

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

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);
    }
}

答案 7 :(得分:1)

您可以创建多个开关:

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;
}

另一种情况仍然需要使用if语句 Oracle在Java 7中添加了使用String的switch语句。也许boolean switch语句将在以后出现。

答案 8 :(得分:0)

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");
        }
    }
}

所以现在你的if

更少了