Control Flow and Collections · Lesson 8 of 41
If-Else and Switch Statements in Apex
Business rules are decisions: discount only for Gold customers, escalate only high-priority cases, route leads by country. Apex gives you two tools – if/else for conditions and switch for choosing between many values – and a third, often-forgotten trick: switching on the type of a record.
In this lesson
- if, else if, else
- Guard clauses that keep code flat
- switch on values, with when null and when else
- switch on sObject types
if, else if, else
Decimal annualRevenue = 4500000;
String rating;
if (annualRevenue == null) {
rating = 'Unknown';
} else if (annualRevenue >= 10000000) {
rating = 'Hot';
} else if (annualRevenue >= 1000000) {
rating = 'Warm';
} else {
rating = 'Cold';
}
System.debug('Rating: ' + rating);
Rating: Warm
Conditions are checked top to bottom and only the first true branch runs, so order matters: put the most specific checks first. Conditions must be real Booleans – Apex has no "truthy" values, so if (name) doesn't compile; write if (String.isNotBlank(name)).
Guard clauses keep code flat
Deeply nested if blocks are hard to read. Return early for the cases you don't handle, and the main logic stays at the left margin:
// DiscountCalculator.cls
public with sharing class DiscountCalculator {
public static Decimal discountFor(Opportunity opp, String customerTier) {
if (opp == null || opp.Amount == null) return 0; // guard clauses
if (opp.StageName == 'Closed Lost') return 0;
Decimal rate = customerTier == 'Gold' ? 0.10 : customerTier == 'Silver' ? 0.05 : 0;
if (opp.Amount > 1000000) rate += 0.02; // volume bonus
return (opp.Amount * rate).setScale(2);
}
}
Opportunity big = new Opportunity(Amount = 2000000, StageName = 'Negotiation');
Opportunity lost = new Opportunity(Amount = 500000, StageName = 'Closed Lost');
System.debug('Gold, big deal: ' + DiscountCalculator.discountFor(big, 'Gold'));
System.debug('Silver, big deal: ' + DiscountCalculator.discountFor(big, 'Silver'));
System.debug('Lost deal: ' + DiscountCalculator.discountFor(lost, 'Gold'));
System.debug('No opportunity: ' + DiscountCalculator.discountFor(null, 'Gold'));
Gold, big deal: 240000.00 Silver, big deal: 140000.00 Lost deal: 0 No opportunity: 0
switch on values
switch compares one expression against several when values. It works with Integer, Long, String (case-sensitive here!), enums and sObjects:
List<String> priorities = new List<String>{ 'High', 'Critical', 'Low', null, 'high' };
for (String priority : priorities) {
String sla;
switch on priority {
when 'Critical', 'High' { // several values in one branch
sla = '4 hours';
}
when 'Medium' {
sla = '1 day';
}
when null { // switch handles null explicitly
sla = 'not set';
}
when else { // everything else (like default)
sla = '3 days';
}
}
System.debug(priority + ' → ' + sla);
}
High → 4 hours Critical → 4 hours Low → 3 days null → not set high → 3 days
Notice the last line: 'high' fell through to when else. Unlike ==, switch on String is case-sensitive. Normalise input first if case shouldn't matter. There's no fall-through between branches and no break – exactly one branch runs.
switch on enums
// CaseChannel.cls
public enum CaseChannel { EMAIL, PHONE, CHAT, PORTAL }
for (CaseChannel ch : CaseChannel.values()) {
switch on ch {
when EMAIL, PORTAL {
System.debug(ch + ': respond in writing');
}
when PHONE, CHAT {
System.debug(ch + ': live response');
}
}
}
EMAIL: respond in writing PHONE: live response CHAT: live response PORTAL: respond in writing
switch on sObject type
When code receives a generic SObject – a polymorphic lookup like Task.WhatId, or a utility that handles several objects – switch can branch on its type and give you a typed variable in one step:
List<SObject> records = new List<SObject>{
new Account(Name = 'Acme', Industry = 'Energy'),
new Contact(FirstName = 'Neha', LastName = 'Rao'),
new Opportunity(Name = 'Acme renewal', Amount = 75000),
new Lead(LastName = 'Shah', Company = 'Globex')
};
for (SObject rec : records) {
switch on rec {
when Account a {
System.debug('Account ' + a.Name + ' in ' + a.Industry);
}
when Contact c {
System.debug('Contact ' + c.FirstName + ' ' + c.LastName);
}
when Opportunity o {
System.debug('Opportunity worth ' + o.Amount);
}
when else {
System.debug('Something else: ' + rec.getSObjectType());
}
}
}
Account Acme in Energy Contact Neha Rao Opportunity worth 75000 Something else: Lead
if or switch?
| Use if/else when… | Use switch when… |
|---|---|
conditions are ranges or combinations (amount > 1000 && isActive) | you compare one value with a list of exact values |
| each branch checks something different | you branch on an enum or a record's type |
| you need case-insensitive String checks | you want explicit when null handling |
Practice
Try it yourself
Write a switch that maps a Lead's
LeadSource('Web', 'Phone Inquiry', 'Partner Referral', anything else) to a queue name.Show answer
switch on lead.LeadSource { when 'Web' { queue = 'Digital_Leads'; } when 'Phone Inquiry' { queue = 'Inside_Sales'; } when 'Partner Referral' { queue = 'Partner_Team'; } when else { queue = 'General'; } }– remember it's case-sensitive, so picklist API values must match exactly.Why doesn't
if (opp.IsWon)throw for a queried Opportunity, whileif (myFlag)might?Show answer
Checkbox fields on records are never null, but a Boolean variable that was never assigned is null, and a null Boolean in a condition throws a NullPointerException.
Quick check
Is switch on String case-sensitive?
Yes – unlike ==.
What is the switch equivalent of default?
when else.
Can switch branch on a record's object type?
Yes – when Account a { … } gives you a typed variable.
Summary
- if/else for ranges and combined conditions; order branches from specific to general.
- Use guard clauses to keep logic flat.
- switch for exact values and enums, with when null and when else; it's case-sensitive for Strings.
- switch on SObject gives typed variables for polymorphic records.
Finished this lesson?
Mark it complete to track your progress, then carry on with the next lesson.