if / else if chain with no final else
ID |
apex.maintainability.missing_final_else |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Control Flow |
Language |
Apex |
Description
Reports an if / else if chain that ends without a final else branch. A trigger-context dispatch chain, which is exhaustive by construction, is not reported.
Rationale
A chain of conditions enumerates the cases the author had in mind; without a final else there is no answer for the case nobody thought of. In Apex that case arrives as a new picklist value, a new record type or a null the query returned, and the chain simply falls through: the variable keeps whatever it had, the method returns null, and the record is saved with a field the code never set. Nothing throws and nothing is logged, so the defect is found by the person who reads the data weeks later, not by the test run.
The following code illustrates the pattern detected by this rule:
public class ShippingRates {
public static Decimal rate(String country) {
// FLAGGED: if / else if chain with no final else
if (country == 'ES') {
return 4.95;
} else if (country == 'PT') {
return 6.50;
}
return 0;
}
public static String band(Decimal weight) {
if (weight < 1) {
return 'light';
// FLAGGED: if / else if chain with no final else
} else if (weight < 10) {
return 'medium';
} else if (weight < 100) {
return 'heavy';
}
return 'unknown';
}
public static String bandWithDefault(Decimal weight) {
if (weight < 1) {
return 'light';
} else if (weight < 10) {
return 'medium';
} else {
return 'heavy';
}
}
public static Boolean isDomestic(String country) {
if (country == 'ES') {
return true;
}
return false;
}
public static String label(Boolean express) {
if (express) {
return 'express';
} else {
return 'standard';
}
}
public static void dispatch() {
if (Trigger.isBefore && Trigger.isInsert) {
AccountTriggerHandler.handleBeforeInsert(Trigger.new);
} else if (Trigger.isAfter && Trigger.isUpdate) {
AccountTriggerHandler.handleAfterUpdate(Trigger.new, Trigger.oldMap);
}
}
}
Remediation
Close the chain with an else that handles the remaining case explicitly - a default value, an addError on the record, or a thrown exception saying which value was not expected. Where the chain tests a picklist or an enum, a switch on with a when else expresses the same intent and makes the default a required part of the statement.