What Does Safe Navigation Mean In Apex?

Salesforce highlighted a fresh “Safe Navigation Operator” in the Winter ’21 release notes. Take a look here.

My friends and I have engaged in a friendly code review rivalry for years. This new feature is set to conclusively resolve that competition, at least among us.

What’s the conflict about?

Let’s simplify the scenario by outlining two predominant patterns. Both will involve String comparisons in the examples.

The Kessel Alliance prefers code that reads in a natural sequence, mirroring verbal communication order. This pattern aligns closely with what’s commonly observed in practical scenarios. Here, we’ll keep it straightforward (though not entirely foolproof)

Illustration:

public static Boolean isStringTheSame (String variableString) {
    String controlString = 'control string';
    
    return variableString.equalsIgnoreCase(controlString);
}

The head of the Kessel Alliance would tease me endlessly if I left it this way. Should variableString be null, the previous code would trigger a Null Pointer Exception (NPE). Kessel Alliance members prioritize NPE-safe code and would likely opt for something like this instead:

public static Boolean isStringTheSame (String variableString) {
    String controlString = 'control string';
    
    if (String.isNotBlank(variableString)) {
        return variableString.equalsIgnoreCase(controlString);
    } else {
        return false;
    }
}

The rival pattern, which I’ve traditionally employed, tackles two issues simultaneously but might be cumbersome to comprehend. This approach originates from the Pond Empire.

public static Boolean isStringTheSame (String variableString) {
    String controlString = 'control string';
    
    return controlString.equalsIgnoreCase(variableString);
}

Given our certainty that controlString is always non-null, it can be referenced without validation. Even if variableString is null, the method will still safely return false. The previous example might not seem peculiar… until you present it this way (using constants is recommended anyway):

public static Boolean isStringTheSame (String variableString) {
    return 'control string'.equalsIgnoreCase(variableString);
}

Both approaches have their advantages and drawbacks. Numerous variations exist, but for the purpose of this article, we don’t need to delve into all of them. Additionally, I believe it’s beneficial to provide responses to the calling code when specific values (such as null) are prohibited. Robust input validation is essential and merits its own article.

What’s the fuss about?


In the given examples, the additional effort required isn’t substantial in either direction. Let’s experiment with some extreme scenarios involving SObjects.

Kessel Alliance (incorporating safety checks):

public static Boolean isGreatGrandparentAccountSalesforce (Account theAccount) {
    String salesforceAccountName = 'Salesforce';
    if (theAccount != null && 
        theAccount.AccountId != null && 
        theAccount.Account.AccountId != null && 
        theAccount.Account.Account.AccountId != null && 
        String.isNotBlank(theAccount.Account.Account.Account.Name) && 
        theAccount.Account.Account.Account.Name.equalsIgnoreCase(salesforceAccountName)) {
            return true;
    } else {
        return false;
    }
}

Pond Empire:

public static Boolean isGreatGrandparentAccountSalesforce (Account theAccount) {
    String salesforceAccountName = 'Salesforce';
    if (theAccount != null && 
        theAccount.AccountId != null && 
        theAccount.Account.AccountId != null && 
        theAccount.Account.Account.AccountId != null &&  
        salesforceAccountName.equalsIgnoreCase(theAccount.Account.Account.Account.Name)) {
            return true;
    } else {
        return false;
    }
}

As evident from our extreme example, we’re still crafting code that’s unwieldy in both scenarios. This is precisely where the Safe Navigation Operator excels. Here’s the same method written in a manner that satisfies both the Alliance and the Empire.

public static Boolean isGreatGrandparentAccountSalesforce (Account theAccount) {
    String salesforceAccountName = 'Salesforce';
    
    return theAccount?.Account?.Account?.Account?.Name?.equalsIgnoreCase(salesforceAccountName);
}

Significant shift, isn’t it? Once more… input validation holds value. None of these illustrations demonstrate robust input validation or any form of feedback to the calling code. As they stand, they rely on assumptions, and such assumptions often result in code that’s challenging to debug.

Wrap-up

That’s about it… I just wanted to highlight the remarkable nature of this feature.