[SalesForce] Best Practice discussion: Difference between SWITCH and IF/ELSE-IF/ELSE

NOTE: This is not an opinion-based question. Developers often debate the best way to code ways to do the same thing. Please don't close this as opinion-based. It's a good reference for people choosing tools in coding.

Maybe it's that I've never used Case statements in Java, but the wonderfully complex evaluation capabilities of an IF statement seem to make SWITCH (in Apex) unnecessary in some (all?) situations. I'm looking for reasons to use SWITCH, and I can't. Please help?

Reasons to stick with IF/ELSE-IF/ELSE:

  • Follows a fall-through architecture in which the first matching statement is executed and then the whole block exits. Just like in Switch.
  • Any filter that evaluates to true will work in the IF evaluator, and that allows for some complex stuff that's pretty useful.

Reasons to use SWITCH:

  • Forces to a distinct set of evaluated items, so easier to read
  • Limited items means testing each option is easier

Reasons not to use SWITCH:

  • IF works just as well, it seems

From the Apex documentation:
Apex switch statement expressions can be one of the following types.

  • Integer
  • Long
  • sObject
  • String
  • Enum

But no Boolean. I guess my mind just works better on Booleans, which I can get with equal signs, String methods, etc.

Things they have in common, so no advantage:

  • Fall-back (else vs when else)
  • First match is executed and then it exits, so no break statement (docs call this no fall-through. "There is no fall-through. After the code block is executed for a particular when block, the switch statement exits.")

So I guess my question is: When should I use one over the other?

Best Answer

Switch, like the if statement, is a tool. If can do whatever switch can do and more, but it can't do what switch does as efficiently as it does. Switch can drastically reduce the complexity of some code. Just to make a point, I'm going to show you a practical, very meaningful difference.


Schema.DisplayType someType = someField.getDescribe().getType();
if( someType == DisplayType.address || someType == DisplayType.Combobox || someType == DisplayType.Email || 
    someType == DisplayType.EncryptedString || someType == DisplayType.MultiPicklist || 
    someType == DisplayType.Phone || someType == DisplayType.Picklist || someType == DisplayType.String ||
    someType == DisplayType.TextArea || someType == DisplayType.URL) {
        // process as a string
} else if(someType == DisplayType.Date) {
    //now a date
} else if(someType == DisplayType.DateTime) {
    // date time
} else if(someType == DisplayType.Time) {
    // time value
} else if(someType == DisplayType.base64) {
    // binary data
} else if(someType == DisplayTYpe.Currency || someType == DisplayType.Double || someType == DisplayType.Integer) {
    // Do something with numbers
} else {
    // Id or DataCategoryGroupReference or Reference
}

switch on someField.getDescribe().getType() {
    when ADDRESS, COMBOBOX, EMAIL, ENCRYPTEDSTRING, MULTIPICKLIST, PHONE,
            PICKLIST, STRING, TEXTAREA, URL {
        // process as a string
    }
    when DATE {
        // process as a date
    }
    when DATETIME {
        // process as a date time
    }
    when TIME {
        // process as a time
    }
    when BASE64 {
        // binary data
    }
    when CURRENCY, DOUBLE, INTEGER {
        // Do something with numbers
    }
    when ID, DATACATEGORYGROUPREFERENCE, REFERENCE {
        // Id or DataCategoryGroupReference or Reference
    }
}

According to my text editor, the first code example is 915 characters, while the second is 541 characters (counting all comments and white space as tabs).

The first one is an unwieldy mess, the second one is actually quite legible, having removed 18 copies of someType == DisplayType. from the code.


Aside from that, switch comes with a few built-in safety features:

If you forget a { or }, the compiler will let you know. Especially if you're in a hurry and/or tend to forget them:

if(cond1) {
  method1();
  method2();
} else if(cond2)
  method3();
  method4();

Another thing, switch was purpose built for dynamic sObject use. Before we'd have to write:

sObject someRecord = someMap.get(recordId);
sObjectType recordObjectType = someRecord.getSObjectType();
if(recordObjectType == Account.sObjectTYpe) {
  Account accRecord = (Account)someRecord;
  // ...
} else if(recordObjectType == Contact.sObjectType) {
  Contact conRecord = (Contact)someRecord;
  // ...
} // ...

Now, we have a much more elegant:

switch on someRecord {
  when Account accRecord {
    // ...
  }
  when Contact conRecord {
    // ...
  }
  // ...
}

As you've noted, switch has particular limitations (this is actually the first release of it, future enhancements are being considered); the feature was shipped with minimal functionality based on what salesforce.com felt they could deliver on time for the most common use cases.

When you need to compare a single variable to a variety of different conditions, switch is probably the right tool to use. For everything else, there's if-else-if-else chains.

Note that TriggerOperation is specifically designed to take advantage of switch.

If else method:

if(Trigger.isInsert) {
  if(Trigger.isBefore) {
    //
  } else {
    //
  }
} else if(Trigger.isUpdate) {
  if(Trigger.isBefore) {
    //
  } else {
    //
  }
} 

switch on Trigger.operationType {
  when BEFORE_INSERT {
    //
  }
  when AFTER_INSERT {
    //
  }
  when BEFORE_UPDATE {
    //
  }
  when AFTER_UPDATE {
    //
  }
}

This common use case was one of the intended purposes of switch; it removes the "need" to have unnecessarily nested if statements. Of course, this also depends on your specific trigger framework format, but for most people, it's simply less code, more legible.

For many practical cases, if statements will continue to be used as they are today. If statements are very practical in many cases, and switch isn't here to replace if. However, the moment you need to compare one value to many different possible values, switch is often more attractive and makes more legible code.


For what its worth, there is also a roughly 10% improved performance using switch over using an exceptionally large if-else chain. For if-else chains that are large enough to be a significant reduction in code, they will also represent a modest boost in performance as well.


I don't know why you'd want to do this, but you could choose to use a "boolean":

Boolean flag = ...;
switch on String.valueOf(flag) {
    when 'true' { 
        System.debug('Flag is set.'); 
    }
    when 'false' { 
        System.debug('Flag is unset.'); 
    }
}

I can't think of a practical reason for doing this, but this code demonstrates that it's at least possible to do that (but it's one line less efficient than if-else chaining). Also, there may be other practical uses you haven't thought of yet. I understand it's a different bit of code than what you're used to, but it certainly has many practical applications; the larger your if-else chain, the more likely it is that switch can help you declutter and organize your code.


So, at the end of the day, you won't be using switch every day, and nobody's forcing you to change, but switch is there when you have a specific problem that needs to be solved.

Related Topic