switch versus if ... else if ... else

exercise No. 210

Q:

Consider a method computeItemCount() of following signature:

static int computeItemCount() {...}

This method will be called by two different implementations of another method getScore():

Implementation by switch Implementation by if ... else if ... else
public static int getScore() {

   switch (computeItemCount()){
      case 1: return 20;
      case 3: return 50;
      default: return 0;
   }
}
public static int getScore() {

   if (1 == computeItemCount()) {
      return 20;
   } else if (3 == computeItemCount()) {
      return 50;
   } else {
      return 0;
   }
}

An experienced programmer claims these two implementations possibly return different results when executing getScore(). Is she right? Explain your answer.

Tip

  • Though switch...case ... default and if ... else if ... else constructs are closely related there is a principal difference.

  • Consider possible side effects of calling computeItemCount() and provide an example.

A:

switch...case ... default is being implemented as a jump table whereas if ... else if ... else evaluate their corresponding logical expressions as often as either one else if(...) clause matches or the final else is being reached. Thus in the switch...case ... default implementation the computeItemCount() method is being executed exactly once. On contrary the two else if(...) branches may execute computeItemCount() twice in succession. Consider:

public class X {
   private static int itemCount = 2;

    static int computeItemCount() {return itemCount++;}
  ...
   public static int getScore() {/* either switch of if implementation */}
}

On a fresh start switch calling computeItemCount() for the first time receifing the initial itemCount value of 2 will return its default value 0.

On contrary the if ... else if ... else implementation will call computeItemCount() two times:

  1. The first if (1 == computeItemCount()) fails since 1 != 2. This results in incrementing itemCount by 1 to the new value 3.

  2. Now the else if (3 == computeItemCount()) clause succeeds. Thus getScore() returns 50.

In order for both implementations to become aligned we need a small modification on the if side:

public static int getScore() {

   final int itemCount = computeItemCount();

   if (1 == itemCount) {
      return 20;
   } else if (3 == itemCount) {
      return 50;
   } else {
      return 0;
   }
}

This way both implementations are in complete sync. (At least despite runtime efficiency and possible OutOfMemoryErrors)