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

exercise No. 220

Q:

Consider a method computeItemCount() of following signature:

static int advanceItemCount() {...}

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

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

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

  if (1 == advanceItemCount()) {
    return 20;
  } else if (3 == advanceItemCount()) {
    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 advanceItemCount() 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 advanceItemCount() method is being executed exactly once. On contrary the two else if(...) branches may execute advanceItemCount() twice in succession. Consider:

public class X {
   private static int itemCount = 2;

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

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

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

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

  2. Now the else if (3 == advanceItemCount()) 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 = advanceItemCount();

   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)