6

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: Is this just because people don't like IF/ELSE-IF and wanted Switch as well?

closed as primarily opinion-based by Brian Mansfield, glls, crmprogdev, Raul, battery.cord Jun 26 '18 at 3:22

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

12

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.

  • 1
    That's a great explanation. Yes, I agree for enums, logic based on a single type of thing, and logic based on the sObject type. And of course it has the most easily grasped use with the new trigger enum. So for those uses you explained, I agree with you. We'll see what else Salesforce comes out with. For trigger handlers, yes, I think it's a great use - and I think rebuilding handlers will be a good thing. For other uses, it seems to be fairly limited (sObject aside) but has great potential. Thanks! – DavidSchach Jun 25 '18 at 23:15
  • I'm also curious: Are you going to make every method in your handler static? The article by Peter Chittum had a static method and that seemed a bit much. I decided to instantiate the handler class and then to call that handler method, and to allow it to do everything from there. Thoughts? – DavidSchach Jun 25 '18 at 23:50
  • @DavidSchach I personally use a static method in the trigger; that static method is responsible for determining which handler class to execute based on the object and trigger operation (e.g. before insert, after update). There's no "one right way", but it's useful to be consistent. As long as all your triggers follow the same pattern, it'll usually be easy to maintain. – sfdcfox Jun 26 '18 at 0:04
  • @sfdcfox Thank you so much for this example, it put everything in perspective for me! – Arthlete Feb 9 at 6:55
2

The accepted answer here Looping over a list of sObjects that has more than object type shows an Apex-specific extra capability of type matching that is kinda neat.

Personally I'd rate a library feature like Comparator support above a language feature switch, but as I understand it, this was something of a test case to demonstrate that language enhancements can actually be delivered after years of stagnation. Lets hope that more substantial language enhancements are on the way e.g. generics.

Not the answer you're looking for? Browse other questions tagged or ask your own question.